whu1572 Cyy and Fzz[字符串+概率]
2015-04-29 21:05
288 查看
http://acm.whu.edu.cn/land/problem/detail?problem_id=1572
题意:给定n(<=8)个单词和一个长度L(<=14)
问随机写一个L长度的字符串(a..z等概率出现),出现所给单词个数的期望。
两种思路:
------------KMP------------
分别求每一个单词出现的概率相加即可。
求一个单词出现的概率不好求,可以转化为求其不出现的概率
对于某给定单词s,
用dp[i][j][k] 表示长度为i的随机字符串最后一个字符为k,最后k个字符与s[1..k]相等的概率
转移的时候控制k<|s|就可以保证s在随机字符串中不出现。
转移的时候要用到kmp,因为随机字符串加上的字符后可能导致和s[k+1]不匹配
这时候要用kmp来跳到一个合适的匹配位置。
例如,s = "abaa",
有状态dp[i][3]['a'], 表示长度为i的随机字符串后3个字符为"aba"
现在在后面加一个字符'b', 得到四个字符"abab", 和s匹配的长度变成了2
所以要转移到dp[i+1][2]['b']
------------AC自动机------------
用n个字符串建一个自动机,单词结尾出的节点存下单词编号。
然后从根节点开始走,
dp[i][j][k]表示走i步, 走到j, 经过了k这些单词, k是二进制数
最后答案等于 sigma(dp[L][j][k] * bit(k)), bit(k)表示k中1的个数。
题意:给定n(<=8)个单词和一个长度L(<=14)
问随机写一个L长度的字符串(a..z等概率出现),出现所给单词个数的期望。
两种思路:
------------KMP------------
分别求每一个单词出现的概率相加即可。
求一个单词出现的概率不好求,可以转化为求其不出现的概率
对于某给定单词s,
用dp[i][j][k] 表示长度为i的随机字符串最后一个字符为k,最后k个字符与s[1..k]相等的概率
转移的时候控制k<|s|就可以保证s在随机字符串中不出现。
转移的时候要用到kmp,因为随机字符串加上的字符后可能导致和s[k+1]不匹配
这时候要用kmp来跳到一个合适的匹配位置。
例如,s = "abaa",
有状态dp[i][3]['a'], 表示长度为i的随机字符串后3个字符为"aba"
现在在后面加一个字符'b', 得到四个字符"abab", 和s匹配的长度变成了2
所以要转移到dp[i+1][2]['b']
#include <cstdio> #include <cstring> using namespace std; const double PP = 1.0/26.0; const double eps = 1e-8; int n, L; int next[20], a[20]; double f[20][30][30]; char s[20]; double solve(char s[]){ int n = strlen(s+1); for (int i=1; i<=n; i++) a[i] = s[i]-'a'; next[1] = 0; for (int i=2; i<=n; i++){ int j = next[i-1]; while (j && a[j+1] != a[i]) j = next[j]; if (a[j+1] == a[i]) j++; next[i] = j; } memset(f, 0, sizeof(f)); for (int c=0; c<26; c++) f[1][c][c==a[1]] = PP; for (int i=1; i<L; i++) for (int j=0; j<26; j++) for (int k=0; k<n&&k<=i; k++) if (f[i][j][k]>eps){ for (int c=0; c<26; c++){ int nxtj = k; while (nxtj && a[nxtj+1]!=c) nxtj = next[nxtj]; if (a[nxtj+1] == c) nxtj++; f[i+1][c][nxtj] += f[i][j][k]*PP; } } double val = 0; for (int j=0; j<26; j++) for (int k=0; k<n; k++) val += f[L][j][k]; return 1.0-val; } int main(){ int test; scanf("%d", &test); for (int T=1; T<=test; T++){ double ans = 0; scanf("%d %d", &n, &L); for (int i=1; i<=n; i++){ scanf("%s", s+1); ans += solve(s); } printf("%.6lf\n", ans+eps); } return 0; }
------------AC自动机------------
用n个字符串建一个自动机,单词结尾出的节点存下单词编号。
然后从根节点开始走,
dp[i][j][k]表示走i步, 走到j, 经过了k这些单词, k是二进制数
最后答案等于 sigma(dp[L][j][k] * bit(k)), bit(k)表示k中1的个数。
相关文章推荐
- [AC自动机+dp] whu oj 1572 I - Cyy and Fzz
- WHU1572---Cyy and Fzz (AC自动机+dp)
- WHU 1572 Cyy and Fzz (AC自动机 dp )
- WHU 1572 Cyy and Fzz(自动机+DP)
- WHU 1572 Cyy and Fzz(AC自动机+dp)
- SSU 495. Kids and Prizes(概率DP)
- linq 实现查询字符串拼接 : And 和 OR 两种方式
- Codeforce_832B_Petya and Exam_字符串模拟
- Misha and Changing Handles(字符串修改)
- poj 1572 Automatic Editing 字符串
- SGU 495. Kids and Prizes(概率dp)
- To and Fro(字符串规律)
- SGU 495 Kids and Prizes (概率DP)
- Swift Up and Running——字符、Unicode和字符串
- linq 实现查询字符串拼接 : And 和 OR 两种方式
- VK Cup 2016 - Round 2 D. Little Artem and Random Variable(已知两个撒子掷出的点数较大为1,2,...,n的概率,较小为1,2,...,n概率)
- 【CodeForeces】【#291_(div.2)_C】字符串哈希 Watto and Mechanism
- java 日期处理,将字符串转换成日期and时区日期处理
- JS中截取字符串中子串的三种方法substring() , slice() and substr().
- Codeforces Round #399 D-Jon and Orbs(概率DP)