CF441E
首先%xtw,从她那边得到了一个非常巧妙的思路。
首先不难发现,因为最多进行 \(200\) 次操作,所以转成二进制之后前 \(8\) 位的数字是不会影响后面的位数的,因为每次 \(\times2\) 相当于是整体左移一位,相对距离没有影响,而 \(+1\) 能够变化的值不会超过 \(256\)。
设 \(g_{i,s}\) 表示操作 \(i\) 次前八位为 \(s\) 的期望是多少,可以很轻松的维护出答案。
然后它就假了
如果这样写,会发现它 Wa 5 原因是前面四个点都很水。
考虑一下,会发现是漏掉了 \(000000000.....00000\) 的情况,即这八位之外还有 \(0\) 的情况。
很好解决,只需要多开一个数组 \(f_{i,s}\) 表示操作 \(i\) 次得到 \(s\) 的期望后缀 \(0\) 长度就好了,前面转移完全一致,只是 \(s=0\) 的时候需要特判。
然后它还是假了
再思考一下,会发现还是漏了一种情况, \(111111111111.....11111111\),这种情况下再 \(+1\) 会出现一大串的后缀 \(0\) ,而前面那个dp并不能把这个统计进去。
没关系,再开一个数组!
设 \(h_{i,j,s}\) 表示操作 \(i\) 次去掉前八位之后后缀 \(1\) 的个数为 \(j\),前八位为 \(s\) 的期望是多少。比如 \((1100001000)_2\) 对应的 \(j\) 就是 \(2\) ,对应的 \(s\) 就是 \((00001000)_2\) 。
会发现这一部分的转移还是和 \(f,g\) 的差不多,实际上只需要稍微改一下判断就好了。
实际上这一个部分可以和上面的 \(f,g\) 一样开两个数组来实现 \(O(k^2)\) 的时空复杂度。但是我懒
有人或许会提出疑问:这样子不是还是会有一些情况没法判断吗?比如 \(111110\ 11111111\) ,这样再 \(+1\) 不就无法统计上前面新链接上的后缀 \(1\) 吗?
这个确实无法统计,但是可以发现,如果要连接上前面的这一串后缀 \(1\) ,意味着需要再进行 \(255\) 次 \(+1\) 操作,因此这种情况并不会被统计,贡献为 \(0\),不需要考虑。
无论是理解上还是代码长度上均被另一种方法吊打
实现的精细一些是可以做到空间 \(O(k)\),时间 \(O(k^2)\) 的,本人写的是 \(O(k^3)\)。
至于dp具体转移懒得敲公式了,就没在上面说,可以参考下面的代码。
Code
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define ll long long
#define ui unsigned int
il ll read(){
bool f=true;ll x=0;
register char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=false;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(f) return x;
return ~(--x);
}
il void write(const ll &x){if(x>9) write(x/10);putchar(x%10+'0');}
il void print(const ll &x) {x<0?putchar('-'),write(~(x-1)):write(x);putchar('\n');}
il ll max(const ll &a,const ll &b){return a>b?a:b;}
il ll min(const ll &a,const ll &b){return a<b?a:b;}
#define double long double
double f[2][256],g[2][256],h[2][235][256],p;
int count(int x){
int ans=0;
for(;x&&!(x&1);x>>=1) ++ans;
return ans;
}
int ccount(int x){
int ans=0;
for(;x&1;x>>=1) ++ans;
return ans;
}
int cnt[256],cntc[256],x,n;
#define B 255
int main(){
cnt[0]=1,cntc[1]=1;
for(ri i=2;i<256;i+=2) cnt[i]=cnt[i>>1]+1;
for(ri i=3;i<256;i+=2) cntc[i]=cntc[i>>1]+1;
x=read(),n=read(),p=1.0*read()/100;
f[0][x&B]=count(x),g[0][x&B]=1;
h[0][ccount(x>>8)][x&B]=1;
for(ri i=1,o=1;i<=n;++i,o^=1){
memset(h[o],0,sizeof(h[o]));
for(ri j=0;j<232;++j){
for(ri s=0;s<=255;++s){
if(s&128) h[o][j+1][(s<<1)&B]+=h[o^1][j][s]*p;
else h[o][0][(s<<1)&B]+=h[o^1][j][s]*p;
if(s==255){
if(j) h[o][0][0]+=h[o^1][j][s]*(1-p);
else h[o][1][0]+=h[o^1][j][s]*(1-p);
}
else h[o][j][s+1]+=h[o^1][j][s]*(1-p);
}
}
double res=0;
for(ri j=0;j<232;++j) res+=h[o^1][j][B]*(8+j);
f[o][0]=(f[o^1][0]+g[o^1][0]+f[o^1][128]+g[o^1][128])*p+res*(1-p);
g[o][0]=(g[o^1][0]+g[o^1][128])*p+g[o^1][B]*(1-p);
for(ri j=1;j<=255;++j){
g[o][j]=g[o^1][j-1]*(1-p);
if(!(j&1)) g[o][j]+=(g[o^1][j>>1]+g[o^1][j>>1|128])*p;
f[o][j]=g[o][j]*cnt[j];
}
}
double ans=0;
for(ri i=0;i<256;++i) ans+=f[n&1][i];
printf("%.9Lf",ans);
return 0;
}
/*
224314221 19 51
1.590075252
*/