【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
",ans1*(1.-p)+ans2*p);
  return 0;  
}
原文地址:https://www.cnblogs.com/TSHugh/p/8476934.html