【BZOJ 3652】大新闻 数位dp+期望概率dp
并不难,只是和期望概率dp结合了一下.
稍作推断就可以发现加密与不加密是两个互相独立的问题,这个时候我们分开算就好了.
对于加密,我们按位统计和就好了;对于不加密,我们先假设所有数都找到了他能找到的最好的匹配(就是异或后为二进制最高位与n-1相等的最大数)并且算出其异或后的总和,然后我们按位贪心,带着所有的数(一开始我们假设所有的数是小于等于二进制最高位与n-1相等的最大数的所有数)从高位走向低位,每走一步,如果这一位是0,就会导致一半的数在这一位不能是1,减去这一半的数在这一位上的贡献,如果这一位是1,就意味着一半的数往后一定会全部是1,我们把这一半数从我们带着的数中减去,另一半待定(留下).
这样思路清晰,实现简易,只是一定注意贡献不要统计错.
#include <cstdio> typedef double db; typedef long long LL; LL f,bin[61],n,temp; db ans1,ans2,p; int digit[61],bit,i,j; int main(){ scanf("%lld%lf",&n,&p),bin[0]=1,temp=--n;//我的代码需要的是n-1 while(temp)digit[++bit]=temp&1,temp>>=1,bin[bit]=bin[bit-1]<<1; for(i=bit;i>0;--i){ f=temp; if(digit[i])f+=(n&(bin[i-1]-1))+1,temp+=bin[i-2];//这一位如果是1的话,对后面都有贡献,所以要累加temp ans1+=(db)f*(n-f+1)*2.*bin[i-1]; } ans1=ans1/(n+1.)/(n+1.); ans2=(db)(n+1.)*(bin[bit]-1); temp=bin[bit]; for(i=bit;i>0;--i) if(digit[i]&1)temp>>=1; else ans2-=(db)(temp>>1)*bin[i-1]; ans2/=(n+1.); printf("%.6f\n",ans1*(1.-p)+ans2*p); return 0; }
苟利国家生死以, 岂因祸福避趋之。