Codeforces做题记录

\(About\)

感觉做题思维很差,很多题算法都会但就是想不到(捂脸。

滚来做\(CF\)题锻炼思维力。

\(Codeforces\ Round\ \#665\ (Div.\ 2)\)

\(A\)

分两种情况讨论。

\(k >= n\),那么将\(A\)移动到\((k, 0)\)为最优。

\(k < n\),解方程\(n + (n - b) = k\),解得\(b = \frac{2 \times n - k}{2}\),如果\(b\)为整数则答案为零,否则无解。

\(B\)

发现只有\(a_i = 2, b_i = 1\)的时候可以使答案增加,所以贪心的先使这样匹配的数目最多。

当数列中不存在\(2\)时,\(a_i = 1\)或者\(a_i = 0\)对答案的贡献都是\(0\),即不会使答案变劣。

\(a_i = 1, b_i = 2\)时答案会减少二,所以尽量避免这样的情况出现,就要使\(a\)中剩下的\(2\)\(0\)尽量和\(b\)中的\(2\)匹配,若不这样做,则会出现\(a_i = 1, b_i = 2\)的情况答案会减少,所以这样贪心是对的。

\(C\)

发现题中所给操作等价于数列中是最小数的倍数的数之间能随意更换位置,剩下的数不能更换位置。

那么为了使数列单增,将所有是最小数的倍数的数进行排序再放回原来的位置,若所得到的数列是递增的则有解否则无解。

\(D\)

贪心的算出每条边的贡献,然后分两种情况讨论。

\(m <= n - 1\),则直接用贡献大的乘大的质因子。

\(m > n - 1\),则将最大的\(m - n + 2\)个质因子相乘与贡献最大的匹配,剩下的依次匹配即可。

\(E\)

发现区域数量加一的情况分为两种。

第一种是某条线段和两条矩形边界相交。

第二种是某条横线段和竖线段相交。

然后用扫描线维护求一下相交个数即可。

\(F\)

题面所给看着就很像线段树的区间划分。

\(tag[k]\)表示第\(k\)层线段树的左右儿子是否交换,第\(k\)层线段树存所有长度等于\(2 ^ k\)的区间。

这样二操作就是从\(0\)\(k\)层标记全部与一异或。

三操作就是第\(k\)层标记全部与一异或。

考虑这样状态下的查询和修改操作,如果打上了标记则进入该进入的另外一个儿子即可,最后复杂度和只有单点修改区间查询的复杂度是一样的。

\(Codeforces\ Round\ \#664\ (Div.\ 2)\)

\(A\)

注意到所有颜色数量中有小于等于一个奇数的时候可以构成回文,由此我们知道只关心颜色数量的奇偶性,所以只需要做一次操作(如果可以),然后再次检查奇偶性即可。

\(B\)

先走到棋子所在的那一行的第一列然后开始一行一行轮流遍历即可,注意不能再走到一开始棋子所在的地方。

\(C\)

注意到最后的答案\(A\)满足所有的\(C_i\ or\ A = A\),注意到可能的值域非常小只有\(2^9\),所以可以枚举最后的答案,然后\(n^2\)枚举看看能不能找到\(C_i\)满足条件,复杂度\(O(2^9 \times n^2)\)

\(D\)

\(>m\)的定义为大项目,其他的定义为小项目,注意到\(x\)个大项目会占用\((x - 1) * (d + 1) + 1\)天,剩下的\(n - (x - 1) * (d + 1) - 1\)天选小项目。

那么枚举多少天选大项目,剩下的选小项目,贪心的每次选最大的即可,有一些细节需要特判一下。

\(E\)

注意到只把图中按照规则要走的边单独拎出来,是一张新的图,这张图满足每个点都只有一条出边,因为最后每个节点都能走回自己,所以是一堆环,那么就还有一个性质:每个点都只有一条入边。

这样所有的边到达的节点的并集就是\(1-n\)的所有点了。

那么预处理出度为\(i\)的点走第\(j\)大边的集合,然后\(k!\)的复杂度枚举所有可能性,看看最后这些到达的边的并集是否等于全集。

这里判断集合相等使用哈希即可。

\(F\)

要用到线性规划,还没学,暂时咕咕咕~

\(Educational\ Codeforces\ Round\ 94\ (Rated\ for\ Div.\ 2)\)

\(A\)

考虑到每个子字符串中都出现了第\(n\)个字符,所以直接把第\(n\)个字符输出\(n\)次即可。

\(B\)

枚举自己拿了多少个剑和斧子中较轻的,这样就能推出随从和自己拿物品的方案,所有情况取最大值就行。

\(C\)

考虑\(0\)的限制比\(1\)严格,所以先看看哪些位置必须为\(0\),然后看\(1\)的限制能不能满足,如果可以把剩下的所有位置都设为\(1\)

\(D\)

枚举\(i\)\(k\),然后只需对每次\(i\)\(j\)之间的\(j\),找到有多少\(> k\)的位置和它权值相同,发现在枚举\(j\)的时候,所找的位置可以通过消去和加上\(j\)的贡献\(O(1)\)转移,所以总复杂度\(O(n ^ 2)\)

\(E\)

考虑对于区间\([l, r]\),每次不是做\(r - l + 1\)次二操作,就是对区间做\(min_{i = 1}^{r} a_i\)次一操作,使得其中一个位置变为\(0\),然后递归到两个子区间里,最多只会递归\(n\)层,每层要找一下最小值,最优可以做到\(O(1)\),所以总体复杂度是可以做到\(O(n)\)的。

\(F\)

咕咕咕~

\(G\)

咕咕咕~

\(Codeforces\ Round\ \#666\ (Div.\ 2)\)

\(A\)

把所有字符的出现次数加进一个大小为\(26\)的桶,看看总和\(mod\)字符串个数是不是\(0\)即可。

\(B\)

先对所给序列排序。

注意到\(2^32\)就会比\(1e9\)大,所以存在一个阈值使得最优的幂序列全部为\(1\),注意到这个值应该在\(2^x = 1e5 \times 1e9\)的时候取到,长度大于\(x\)的直接输出所有数的和减去数的个数即可。

否则注意到因为是幂序列,所以要尽可能的使最后一个数的贡献最小,这样找到最小的\(x\)\(n\)次幂大于等于最后一个数,再试试它减一的答案即可。

\(C\)

先把第一个数变成\(0\)

把剩下的\(n - 1\)个数加上\((n - 1) \times a_i\),这样一定是\(n\)的倍数。

最后把所有的数加上\(-a_i\)即可。

\(D\)

如果有一堆石子大小大于所有的石子的和除以二,那么先手可以一直拿这堆石子,先手必胜。

然后如果所有的石子的和是奇数则先手胜,否则后手胜。

\(E\)

注意到每个点可能的方案是直接从上一个推过来或者是从上面的某点开始形成一个环。

\(dp_i\)表示前\(i\)个关卡通关的最少时间。

若从上个点打过来则有

\[dp_i = dp_{i - 1} + r1 * a_i + r3 \]

对于另外一种情况,先预处理\(s_i\)表示不考虑题目中所给限制前\(i\)关全部通关的最少时间,枚举环的起点,那么有

\[dp_i = min\ dp_j + s_i - s_j + (i - j - 1) \times 3d + d\ (0 <= j <= i - 2) \]

对于\(i = n\)时,可以最终不会到\(n\)节点,那么有

\[dp_i = min\ dp_j + s_n - s_j + (n - j - 1) \times 2d + d + r1 \times a_n + r3\ (0 <= j <= n - 2) \]

\(Codeforces\ Round\ \#674\ (Div.\ 3)\)

\(A\)

按照题意,如果序号\(<=2\),那么答案是\(1\),否则是\((n - 2 + x - 1) / x + 1\)

\(B\)

如果输入的\(m\)是奇数那么不行,如果输入的矩阵中没有满足\(a_{2,1} = a_{1,2}\)的,那么不行。

\(C\)

假设所有操作做完之后最大的值是\(x\),那么答案是\(\frac{n - 1}{x} + x - 1\)

这玩意取到最小值就是\(x = \sqrt(n)\)的时候。

\(D\)

做个前缀和,不存在子段为\(0\)就是要用\(INF\)隔开所有相等的前缀和。

这样从左往右扫前缀和数组,看看上一次最后放的\(INF\)能不能把现在的前缀和值和最后和当前前缀和值相等的位置隔开,不能就再放一个。

\(E\)

尽量多的赢的方案数比较容易算就是\(min(a_0,b_1) + min(a_1, b_2) + min(a_2, b_0)\)

然后尽量少的方案数只需要爆搜所有的可能性取\(min\)

\(F\)

没有\(?\)的情况下是好统计的,有\(?\)的时候可以枚举所有最后的状态中\(?\)占了哪些位置分别算。

但其实不用这么麻烦,\(dp_{i, 0}\)表示什么都不满足的序列有多少个,\(dp_{i,1}\)表示能取一个\(a\)的数列有多少个,\(dp_{i, 2}\)表示能取\(a,b\)的数列有多少个,\(dp_{i,3}\)表示能取\(a,b,c\)的数列有多少个。

转移代码如下

懒得手打了(不是

	dp[0][0] = 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= 3; j++) dp[i][j] = 1LL * dp[i - 1][j] * (st[i] == '?' ? 3 : 1) % MOD;
		if (st[i] == 'a') dp[i][1] = (0LL + dp[i][1] + dp[i - 1][0]) % MOD;
		if (st[i] == 'b') dp[i][2] = (0LL + dp[i][2] + dp[i - 1][1]) % MOD;
		if (st[i] == 'c') dp[i][3] = (0LL + dp[i][3] + dp[i - 1][2]) % MOD;
		if (st[i] == '?') 
		{
			dp[i][1] = (0LL + dp[i][1] + dp[i - 1][0]) % MOD;
			dp[i][2] = (0LL + dp[i][2] + dp[i - 1][1]) % MOD;	
			dp[i][3] = (0LL + dp[i][3] + dp[i - 1][2]) % MOD;
		}
	}
posted @ 2020-08-24 18:17  Tian-Xing  阅读(365)  评论(0编辑  收藏  举报