ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

abc227 题解

2021-11-17 22:01:50  阅读:144  来源: 互联网

标签:lof int 题解 MAXN ans include abc227 dp


考场上没状态啊


A

用周期性算即可。


B

枚举。


C

发现 \(A\le \sqrt[3] N\),\(B \le \sqrt N\),直接枚举,发现能跑过。复杂度不会证,好像要用微积分。
我考场不知道在想什么,枚举 \(B\) 的时候用的整除分块。。。复杂度是一样的,但常数大T了。


D

一个很自然的想法是 考虑选数删除的过程,发现优先选当前最大的 \(k\) 个一定最优,但时间复杂度飞了。
又有一个很常见的 trick 是:我们不考虑选数的过程,而是考虑每个会对答案产生多少贡献。发现如果最后要选 \(t\) 组出来,\(a_i\) 提供的贡献理论上最大是 \(\min(t,a_i)\),而我们每次二分这个 \(t\) 即可。


E

想法不要轻易扔了

显然直接模拟这个交换过程是不行的。考虑要得到一种序列最多只会交换 \(n\) 次。
那便可以很自然的引出这样一个dp状态:dp[构造出前i个数][有几个K][有几个E][有几个Y][交换了g次]能构造出最后的数列的方案数。这里其实有个很常见的 trick 吧————直接构造答案序列。在我 之前的博客 中有讲。
然后仔细想一想,发现可以贪心地转移(即尽量互换)。然后随便推推就行了。
(我这样写题解会不会被打)


F

第一感觉是 dp。发现这个第 \(k\) 大(而且还要求和)不好动态维护。
trick:我们考虑设置一个阈值 \(p\),即第 \(k\) 大的数字,如果当前数大于等于 \(p\),就加上他的贡献。那如何保证这个数一定是第 \(k\) 大?
Reply:不就是比他大的有 \(k-1\) 个吗?哈哈哈哈sb,如果这条路径没经过值等于 \(p\) 的数,那你会发现这条路径只加了 \(k-1\) 个。而且如果相同的数很多,可能多加了这些相同的数。
解决办法:对于当前值等于阈值 \(p\) 的时候,特殊处理:可以使其选或不选。
所以对于每个数我们跑个 dp,时间复杂度:\(\mathcal {O}(H^2W^2k)\)。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define LL long long
#define uint unsigned int
using namespace std;
const int MAXN = 35;
const LL lof = 4e18;
int n, m, k, a[MAXN][MAXN];
LL ans = lof, dp[MAXN][MAXN][MAXN << 1];
LL Calc(int x, int y) {
	for(int i = 1; i <= max(n, m); i ++) for(int j = 0; j <= k; j ++) dp[i][0][j] = dp[0][i][j] = lof;
	dp[0][1][0] = 0;
	for(int i = 1; i <= n; i ++) {
		for(int j = 1; j <= m; j ++) {
			if(a[i][j] == a[x][y]) {
				for(int u = 0; u <= k; u ++) {
					dp[i][j][u] = lof;
					if(u) dp[i][j][u] = min(dp[i - 1][j][u - 1], dp[i][j - 1][u - 1]) + a[i][j];
					dp[i][j][u] = min(dp[i][j][u], min(dp[i - 1][j][u], dp[i][j - 1][u]));
					if(dp[i][j][u] > lof) dp[i][j][u] = lof;
				}
			}
			else if(a[i][j] > a[x][y]) {
				dp[i][j][0] = lof;
				for(int u = 1; u <= k; u ++) {
					dp[i][j][u] = min(dp[i - 1][j][u - 1], dp[i][j - 1][u - 1]) + (a[i][j] >= a[x][y] ? a[i][j] : 0);
					if(dp[i][j][u] > lof) dp[i][j][u] = lof;
				}
			}	
			else {
				for(int u = 0; u <= k; u ++) {
					dp[i][j][u] = min(dp[i - 1][j][u], dp[i][j - 1][u]) + (a[i][j] >= a[x][y] ? a[i][j] : 0);
					if(dp[i][j][u] > lof) dp[i][j][u] = lof;
				}
			}
	//		for(int u = 0; u <= k; u ++) printf("%d %d %d %lld\n", i, j, u, dp[i][j][u]);
		}
	}
//	printf("|%d %d %d %lld|\n", x, y, k, dp[n][m][k]);
	return dp[n][m][k];
}
int main() {
	scanf("%d%d%d", &n, &m, &k);
	for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) scanf("%d", &a[i][j]);
	for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) ans = min(ans, Calc(i, j));
	printf("%lld", ans);
	return 0;
}

G

定义 \(a\sim b=a\times(a+1)\times (a+2)...\times b\)。
\(k\) 很小。所以我们可以把最后的式子化为 \(\frac {(n+k-1)\sim n}{1\sim k}\)。
凭借直觉,根据唯一分解定理(即因数个数等于指数相加再连乘),我们自然想到分类讨论(根号分治)。

  1. \(p>\max(k,\sqrt n)\)(\(p\) 为质数)。这样的 \(p\) 只会整除分子一次,不会整除分母。所以我们应该考虑怎么消掉 \(\le k\) 的质因子。
  2. \(p\le\max(k,\sqrt n)\)(\(p\) 为质数)。这样的 \(p\) 约有 \(n/\ln(n)\) 个。首先对于每个质数可以用 \(log_p\) 的方法求出区间内的数乘起来它的指数。考虑用埃筛的方法,将 \([n-k+1,n]\) 中的数中 \(<p\) 地因子全部约掉,复杂度 \(<\mathcal {O}(klog)\)。剩下的就是 \(p>k\) 的因子了,然后这道题就做完了,也不是很难,考虑筛质数的基本功。
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define LL long long
using namespace std;
const int Mod = 998244353, MAXK = 1e6 + 5;
LL n, a[MAXK], ans = 1;
int k, pr[MAXK], tot, N;
bool vis[MAXK];
void Prime() {
	for(int i = 2; i <= N; i ++) {
		if(!vis[i]) pr[++ tot] = i;
		for(int j = 1; j <= tot && i * pr[j] <= N; j ++) {
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0) break;
		}
	}
}
LL Calc(int p, LL l, LL r) {
	LL res = 0;
	for(LL i = p; i <= r; i *= p) {
		res += r / i - (l - 1) / i;
	}
	return res;
}
int main() {
	scanf("%lld%d", &n, &k);
	N = max((int)sqrt(n) + 1, k); 
	Prime();
	for(int i = 1; i <= k; i ++) a[i] = n - k + i;
	for(int i = 1; i <= tot; i ++) {
		LL t = Calc(pr[i], n - k + 1, n) - Calc(pr[i], 1LL, (LL)k);
		ans = (ans * ((t + 1) % Mod)) % Mod;
	}
	for(int i = 1; i <= tot; i ++) {
		for(LL j = (n - k + 1) / pr[i] * pr[i]; j <= n; j += pr[i]) {
			if(j < n - k + 1) continue;
			while(a[j - n + k] % pr[i] == 0) a[j - n + k] /= pr[i];
		}
	}
	for(int i = 1; i <= k; i ++) {
		if(a[i] > 1) ans = ans * 2 % Mod;
	}
	printf("%lld", ans); 	
	return 0;
}

标签:lof,int,题解,MAXN,ans,include,abc227,dp
来源: https://www.cnblogs.com/Kidulthood/p/15569720.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有