1. 程式人生 > >【BZOJ 3652】大新聞 數位dp+期望概率dp

【BZOJ 3652】大新聞 數位dp+期望概率dp

貢獻 ble emp cst return post turn www 註意

並不難,只是和期望概率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; }

【BZOJ 3652】大新聞 數位dp+期望概率dp