2016 ACM-ICPC NEERC F. Foreign Postcards
题意:有一串由C、W组成的字符串,每次截取长度为k(1<=k<=n且k随机)的前缀,如果该前缀首位为W,则该前缀取反(即C->W,W->C),放到桌上,否则直接放到桌上;重复前面步骤直至字符串被截为空。求最后桌上W的个数期望。
思路:定义dp[i]:以s[i]为首的后缀的W个数期望
则dp[i]=Σ{ (dp[k]+“s[i]到s[k-1]的W或C的个数”)/(n-i) }(i+1<=k<n,s[i]为W时,加C的个数,s[i]为C时直接加W的个数)
观察式子可以发现,应该倒着推,因为当前状态由后缀状态累加后转移而来。倒着推的过程中,注意累加dp结果以及C,W的个数(这里W,C的个数,指的是当前后缀中所有前缀的C,W个数和,写几项DP转移式可以发现需要维护这些值)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#define dd(x) cout<<#x<<" = "<<x<<" "
#define de(x) cout<<#x<<" = "<<x<<endl
using namespace std;
typedef long double ld;
typedef long long ll;
const int maxn=1e6+10;
char s[maxn];
int main()
{
freopen("foreign.in","r",stdin);
freopen("foreign.out","w",stdout);
scanf("%s",s);
int n=strlen(s);
ll cntc=0,cntw=0;
ld exp=0,ans=0;
for (int i=n-1;i>=0;--i)
{
int p=n-i;
if (s[i]=='C')
{
cntc+=p;
ans=(exp+cntw)/p;
exp+=ans;
}
else
{
cntw+=p;
ans=(exp+cntc)/p;
exp+=ans;
}
}
printf("%.14Lf",ans);
return 0;
}