2016 ACM-ICPC NEERC F. Foreign Postcards (概率DP)

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;
}
原文地址:https://www.cnblogs.com/orangee/p/9735610.html