Codeforces Round #691 (Div. 2)

\(Rating\)上涨了,真开心

A - Red-Blue Shuffle

给你\(n\)张牌,每张牌上有一个红色的数字和一个蓝色的数字,你可以将牌随便排序,问你是红色组成的数字大于蓝色的概率大,还是蓝色组成的数字大于红色的概率大,还是两者相等。

哪种颜色的数字大的数量多,哪种颜色概率就大,签到题

B - Move and Turn

找规律+结论题

有一个无限展的二维平面,一个机器人每秒可以前进一个单位,但是每一秒之后,机器人必须向左转或者向右转。问你\(n\)秒之后机器人可能出现的坐标的数量。

找规律的话,就先用\(bfs\)打表(注意\(bfs\)会爆内存),然后就能发现规律:

  • \(n\)是偶数,则答案为\((n / 2 + 1)^2\)

  • \(n\)是奇数,则答案为\(k=\frac{n}{2},2*(k+1)(k+2)\)

考虑\(n\)为偶数时的情况。无论初始方向如何,我们将进行\(n/2\)个水平步和\(n/2\)个垂直步。此外,水平和垂直步数的方向可以单独决定。

比如有\(k\)个水平方向的选择,那么最后的落点横坐标就是\([-k,-k+2,.....k]\)

则偶数答案为\((n/2+1)^2\)

奇数的情况需要考虑第一步是水平的还是垂直的,这里首先说明一个结论

最终的水平位置x的奇偶性与水平步数相同

由此得出:从垂直和水平步数开始都不可能到达相同的位置

\(n=2k+1\)是奇数。如果我们从水平步开始,那么总共将进行\(k+1\)个水平步和\(k\)个垂直步,那么最后到达点数是\((k+1)*(k+2)\)(可以参考偶数情况理解)

最后答案就是\(2*(k+1)*(k+2),k=n/2\)

本题告诉我们,像这类在二维坐标系上移动的题目:

  • 可以单独分离出横纵坐标,然后利用简单计数原理进行求解

  • 从奇偶数角度考虑

C - Row GCD

数论+思维+差分

给定数组\(a[n],b[m]\),对于每个\(b_i,i\le m\),求\(\gcd(a_1+b_i,a_2+b_i.....)\)

很妙的题目,平时\(gcd\)的题目很少用的\(\gcd(a,b)=\gcd(a-b,b)\)这个性质,本题就是利用这个性质来求解

同理\(\gcd(x,y,z)=\gcd(x-y,y,z)\)依然成立,那么求解\(\gcd(a_1 + b_j, \ldots, a_n + b_j)\)时,可以把第二项往后减去第一项,即\(\gcd(a_1 + b_j, \ldots, a_n + b_j) = \gcd(a_1 + b_j, a_2 - a_1, \ldots, a_n - a_1)\)

这时候我们可以发现\(\gcd\)式子里面除去第一项外都是定值了,这时候可以分离一下

\(X=\gcd(a_2-a_1,...,a_n-a_1)\),题目变成了求解\(\gcd(a_1+b_j,X)\)

D - Glass Half Spilled

\(DP\)

桌子上有\(n\)个玻璃杯,编号为\(1,...,n\)。第\(i\)个玻璃杯最多可以装\(a_i\)单位的水,目前装的是\(b_i\)单位的水。

选择\(k\)个玻璃杯,可以把\(x\)(不超过\(c_i\),可以是实数)单位水从\(i\)杯转移到\(j\)杯,水会撒一半(\(j\)杯超出部分也会溢出),问最后\(k\)个玻璃杯最大水量为多少(误差不超过\(10^{-9}\))

设最初所有杯子水的和是\(s_1\),最后选择的\(k\)杯水和是\(s_2\),容量是\(s_3\)

显然,其他杯子最多能给我们选择的倒出\((s_1-s_2)/2\)

答案就是\(\max(s_3,s_2+(s_1-s_2)/2)=\max(s_3,(s_1+s_2)/2)\)

现在未知数就是\(s_2,s_3\)

\(f[i][j][k]\)表示前\(i\)个水杯,选了\(j\)个,容量\(s_3=k\)时最多能放的水量,这样就成功联系起来了\(s_2,s_3\)

现在问题变为:有一个背包,容积为\(k\),能拿\(j\)个物品,问最大价值。

思路源自大神qscqesze

const int N = 220, M = 1e4 + 2020;
int n, dp[N][M], a[N], b[N], suma, sumb; 
int main()
{
  	n = read();
  	for(int i = 1; i <= n; ++i){
  		a[i] = read(), b[i] = read();
  		suma += a[i], sumb += b[i];
	}
	for(int i = 0; i <= n; ++i)
		for(int j = 0; j <= M; ++j)
			dp[i][j] = - 1e9;
	dp[0][0] = 0;
	for(int i = 1; i <= n; ++i)
		for(int j = n; j >= 1; --j)//???为什么正序不行呀 
			for(int k = suma; k >= a[i]; k--)
				dp[j][k] = max(dp[j][k], dp[j - 1][k - a[i]] + b[i]);		
	for(int i = 1; i <= n; ++i){
		double ans = 0.0;
		for(int k = 0; k <= suma; ++k){
			ans = max(ans, min( (dp[i][k] * 1.0 + sumb ) / 2.0, k * 1.0 ) );
		}
		printf("%.10lf ", ans);	
	}		
	return 0;
}

\(DP\)还是弱,经典\(DP\)问题不会处理

posted @ 2020-12-20 22:09  pyyyyyy  阅读(96)  评论(2编辑  收藏  举报