【解题报告】CF Round #320 (Div. 2)
Raising Bacteria
题意:盒子里面的细菌每天会数量翻倍,你可以在任意一天放任意多的细菌,最后要使得某天盒子里面的细菌数量等于x,求至少要放多少个细菌
思路:显然,翻倍即为二进制左移一位,那么放入一个细菌,到第二天就变成2个二进制下即为1->10对于任意二进制数 如:1001110,只需要在第一天放1个,第4、5、6天各放一个,再等一天,就可以了。所以答案显然是x在二进制下1的个数。
Finding Team Member
题意:2n个人,每两个人组合的队伍有aij的力量。每个人都希望组合的队伍力量最大。求最终会怎么组合。
思路:找出矩阵中最大的那个数字aij,显然ij会组成一队,然后ij已经组队了,把和ij有关的行列都删除,然后再找出剩下的最大组合。依次类推即可以出答案。
直接在矩阵中找显然会超时。我们可以把矩阵的每条排序,然后从大到小依次扫描并标记每个人的队友,扫描到一个值的时候先判断对应的ij是否已经组队,如果已经组队就跳过这一项。
A Problem about Polyline
题意:折线经过点(0, 0) – (x, x) – (2x, 0) – (3x, x) – (4x, 0) – ... - (2kx, 0) – (2kx + x, x) – ...。给定一个坐标(a,b)求最小的x使得折线经过点(a,b)。
思路:先计算出经过那点之后第一次碰到x轴的位置的坐标(a+b,0),然后求出这个点的x坐标在总的几分点上。即(a+b)/b。然后向上取到2的倍数,即为这段折线有多少条线段组成。然后就可以计算x了。
"Or" Game
题意:给定一个数列,你可以操作k次,每次选择其中的一个数字把它乘以x,求这样操作完成后,使所有数字进行或运算的结果最大。
思路:考虑所有数字的二进制。如果有一个数字的二进制位数最大,那么一定是把所有操作都用在这个数字上,因为乘以x之后这个数字的二进制位数会增加,而且所有数字或运算后结果的二进制位数等于这个数列里面最大的二进制位数,因此把所有操作用在那个本来就最大的二进制位数上的话,二进制位数就会最大(因为x大于等于2)。
这样考虑完之后,如果有多个数字的二进制位数最大且相同呢?那么首先考虑第一次操作肯定会操作在这些数字的某一个上,而且操作完之后,这个数字就变成唯一一个二进制位数最大的了,那么接下来的操作肯定也是在这个数字上的,所以可以得出结论,k次操作都会用在同一个数字上!
至于哪一个,直接遍历就好了~
值得注意的是,遍历的时候,可以先预处理出o[i]=a[0]|a[1]|...|a[i-1]|a[i+1]|a[i+2]|...|a[n-1],这一步可以O(n)完成,然后计算出第i个位置的值再和o[i]取或。
o[i]的话,先预处理出左半边:a[0]..a[i-1],再处理右半边a[i+1]...a[n-1]。分两步正反各扫描一次即可完成。
Weakness and Poorness
题意:给定一个序列a1~an,求一个x使得a1-x,a2-x,...,an-x的 weakness 最小。
weakness 定义为序列的 最大的 子序列的poorness
poorness是这个序列的和的绝对值
思路:假定只有一个序列,我们求一个x使得这个序列的poorness最小。把x作为自变量,这个poorness的结果作为函数f(x)的话,可以得知f(x)是个凸函数(先增大,后变小,中间可能有一段不变)。
于是我们要求的问题变成 g(x)=min(f1(x),f2(x)...)。可以得知g(x)也是凸函数。g(x)这个函数的函数值可以通过dp求解。就是最大连续子段和的dp啦。
于是问题就是求g(x)这个凸函数的极值问题了,直接套三分求解即可。
PS:这题的精度卡的有点紧。。。
#include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> #include<map> #include<queue> #include<set> using namespace std; #define CIN(x) scanf("%d",&x) #define FOR(i,n) for(i=0;i<(n);i++) #define CLR(a,v) memset(a,(v),sizeof(a)) int a[200005]; int n; double f(double x){ double ans1=0,ans2=0; double ansans1=0,ansans2=0; for(int i=0;i<n;i++){ ans1=max(ans1+(a[i]-x),(a[i]-x)); ansans1=max(ans1,ansans1); ans2=min(ans2+(a[i]-x),(a[i]-x)); ansans2=min(ans2,ansans2); } return max(ansans1,-ansans2); } double sanfen(double l,double r){ double mid,midmid,fmid,fmidmid; mid=(l+r)/2; midmid=(mid+r)/2; fmid=f(mid); fmidmid=f(midmid); while(r-l>0.00000000001){ if(fmid>fmidmid){ l=mid; mid=midmid; fmid=fmidmid; midmid=(mid+r)/2; fmidmid=f(midmid); }else{ r=midmid; midmid=mid; fmidmid=fmid; mid=(l+midmid)/2; fmid=f(mid); } } return fmid; } int main(){ CIN(n); int ma=-10000,i; int mi=10000; FOR(i,n){ CIN(a[i]); ma=max(a[i],ma); mi=min(a[i],mi); } printf("%.12lf\n",sanfen(mi,ma)); return 0; }
最后一题并不会做。。。