#C240808D. 打字机


#C240808D. 打字机

网址(Website)

题目详情 - 打字机 - Super

题解 - 打字机 - Super

题目(Problem)

题目描述

小A打算创作一首诗歌,使用长度为 $ n \times m $ 的$01$串表示诗句。打字机有 $ p $ 的概率打出正确的数字,有 $ 1-p $ 的概率打出错误的数字。小A想知道,在他采用最优策略时打出好诗歌的概率。

输入格式

  • 从文件 type.in 读入数据。
  • 第一行包含两个正整数 $ n $ 和 $ m $,以及一个浮点数 $ p $。
  • 接下来 $ n $ 行,每行包含一个长度为 $ m $ 的$01$串。

输出格式

  • 输出到文件 type.out
  • 输出一个浮点数代表正确的概率。

样例

输入数据 1

2 3 0.9
010
101

输出数据 1

0.590490000000

样例1解释

小A的策略是:一开始随便打一个数字,如果是 $00$,后续按 $1010110101$ 的顺序操作,成功打出好诗歌概率为 $ (0.9)^5 $。反之按 $0101001010$ 的顺序操作,成功打出好诗歌概率也为 $ (0.9)^5 $。所以按照此策略打出好诗歌的概率为 $ (0.9)^5 = 0.59049 $。

数据规模与约定

对于所有数据,有:

  • $ 1 \leq n, m \leq 1000 $
  • $ 0.5 \leq p < 1 $

测试点

测试点$ n, m \leq $特殊性质
$1\sim 6$$10$
$7\sim12$$1000$$ n = 2^ m$
$13\sim 20$$1000$

题解(Solution)

很明显,对于每一个位置,打印有没有错误的概率是一定的,而每一个串的顺序和答案无关,考虑对每一个 $01$ 串建 $Trie$ 树:对于 $Trie$ 树上的每一个节点,设它的下一位有 $x$ 个 $0$ ,$y$ 个 $1$ ,那么要打出好的串,这个节点至少要被经过 $x+y$ 次。

令 $f(x,y)$ 表示当前节点打出 $x$ 个 $0$ ,$y$ 个 $1$ 的概率,则可以推出:

f[0][0] = 1, f[x][0] = pow(p,x), f[0][y] = pow(p,y);
f[x][y] = max(p*f[x-1][y]+(1-p)*f[x][y-1],p*f[x][y-1]+(1-p)*f[x-1][y]);

最终要求出每个点的 $f(x,y)$ ,由乘法原理,答案为 $\Pi_{p=0}^{p\le idx}f(x,y) $

代码(Code)

#include<bits/stdc++.h>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define int long long
const int N = 1005;
bool ST;

int n,m,a[N];
double p,q;

int t[N*N][2],idx=0;
int cnt[N*N][2];
void insert(string s){
	int p = 0, n = s.length();
	for(int i = 0;i<n;i++){
		int c = s[i] - '0'; 
		cnt[p][c]++;
		if(!t[p][c]) t[p][c] = ++idx;
		p = t[p][c];
	}
}

double f[N][N];
bool ED;
//看到题目就开走,不跑样例是小狗 
//不打暴力是小狗 
signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	freopen("type.in","r",stdin);
	freopen("type.out","w",stdout);
	cin>>n>>m>>p;int Tim = clock();
	For(i,1,n){
		string s;cin>>s;
		insert(s);
	}q = 1 - p;
	
	f[0][0] = 1;//打印 0 个 1 和 0 个 0 的概率为 1 
	For(i,1,n)
		f[i][0] = f[i-1][0] * p, 
		f[0][i] = f[0][i-1] * p;
	For(i,1,n) For(j,1,n)
		f[i][j] = max(p*f[i][j-1]+q*f[i-1][j],p*f[i-1][j]+q*f[i][j-1]);
	
	double ans = 1;
	For(p,0,idx){
		ans *= f[cnt[p][0]][cnt[p][1]];
	}cout<<fixed<<setprecision(12)<<ans<<'\n';
	return cerr<<"TIME:"<<(clock()-Tim)/1000.,0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录