HDU 6086 Rikka with String (AC 自动机+状压 dp, 2017 Multi-Univ Training Contest 5)
来源:互联网 发布:落英纷飞 音乐软件 编辑:程序博客网 时间:2024/06/07 22:47
Problem
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:
Yuta has n 01 strings si, and he wants to know the number of 01 antisymmetric strings of length 2L which contain all given strings si as continuous substrings.
A 01 string s is antisymmetric if and only if s[i]≠s[|s|−i+1] for all i∈[1,|s|].
It is too difficult for Rikka. Can you help her?
In the second sample, the strings which satisfy all the restrictions are 000111,001011,011001,100110.
对给定的 n 个 01 串
其中反回文串指串 s 满足
Limit
Idea
如果不考虑反回文串的问题,此题就是一个简单的 AC 自动机 + dp (当然,需要状压) 的问题。(如果不能理解,请自行搜索)。
由于有反回文的设定,故对于 2L 长的 01 串,当前 L 长已知时,后 L 长必然确定。故考虑三种情况,字符串
- 字符串
si 落在前 L 的问题,直接在 AC 自动机上插入原串si 。 - 字符串
si 落在后 L 的问题,该字符串在前 L 一定呈现了它本身的逆反串(即 reverse(s_i) 同时对每一位的 01 取反)在 AC 自动机上插入原串的逆反串。 - 字符串
si 部分在前 L 部分在后 L 的问题,由于需要区分多少长在前 L ,多少在后 L ,且有部分无法满足反回文串的限制。故需多重考虑。总之,对枚举的合法的可能,构造能使得该串完整出现在该前后 L 结合部分的串ss (具体见jugGapAndInsert()
函数),将其加入 AC 自动机。
AC 自动机在产生 fail 指针后,直接状压 dp 。
Code
#include<bits/stdc++.h>using namespace std;char s[6][22], ss[22];const int maxn = 1000+10;const int mod = 998244353;const int CH = 3;int t, n, L, dp[101][maxn][128];struct Trie { int nxt[maxn][CH], fail[maxn], end[maxn], isEnd[maxn]; int root, L; void init() { L = 0; root = newnode(); } int newnode() { for(int i=0;i<CH;i++) nxt[L][i] = -1; isEnd[L] = 0; end[L++] = 0; return L-1; } void insert(char buf[], int len, int idx, bool flg) { int p = root; for(int i=0;i<len;i++) { if(nxt[p][buf[i]] == -1) nxt[p][buf[i]] = newnode(); p = nxt[p][buf[i]]; } if(flg) isEnd[p] |= (1<<idx); else end[p] |= (1<<idx); isEnd[p] |= (1<<idx); } void build() { queue<int> que; fail[root] = root; for(int i=0;i<CH;i++) if(nxt[root][i] == -1) nxt[root][i] = root; else fail[nxt[root][i]] = root, que.push(nxt[root][i]); while(!que.empty()) { int p = que.front(); que.pop(); for(int i=0;i<CH;i++) if(nxt[p][i] == -1) nxt[p][i] = nxt[fail[p]][i]; else { fail[nxt[p][i]] = nxt[fail[p]][i]; que.push(nxt[p][i]); } } } void debug(){ for(int i = 0;i < L;i++) { printf("id = %2d,fail = %3d,end = %3d, isEnd = %d, chi = [",i,fail[i],end[i],isEnd[i]); for(int j = 0;j < CH;j++) printf("%3d",nxt[i][j]); printf("]\n"); } }}ac;void jugGapAndInsert(int idx, int gap) { for(int i=0;;i++) { if(gap+i+1 == strlen(s[idx]) || gap-i < 0) break; if(s[idx][gap+i+1] == s[idx][gap-i]) return; } int len = strlen(s[idx]); if(gap+1 > len-gap-1) { ac.insert(s[idx], gap+1, idx, true); } else { for(int i=0;i<len-gap-1;i++) ss[i] = 3 - s[idx][len-i-1]; ac.insert(ss, len-gap-1, idx, true); }}int main(){ scanf("%d", &t); while(t-- && scanf("%d %d", &n, &L)!=EOF) { ac.init(); memset(dp, 0, sizeof(dp)); for(int i=0, len;i<n;i++) { scanf(" %s", s[i]); len = strlen(s[i]); for(int j=0;j<len;j++) { s[i][j] = s[i][j] - '0' + 1; ss[len-j-1] = 3 - s[i][j]; } ac.insert(s[i], len, i, false); ac.insert(ss, len, i, false); for(int j=0;j<len-1;j++) jugGapAndInsert(i, j); } ac.build(); //ac.debug(); dp[0][0][0] = 1; for(int i=0, nxt, tmpNxt, status, isEnd;i<L;i++) for(int j=0;j<ac.L;j++) for(int c=1;c<=2;c++) { nxt = j; status = 0, isEnd = 0; nxt = ac.nxt[nxt][c]; tmpNxt = nxt; while(tmpNxt != 0) { status |= ac.end[tmpNxt]; if(i+1==L) status |= ac.isEnd[tmpNxt]; tmpNxt = ac.fail[tmpNxt]; } for(int S=0;S<(1<<n);S++) (dp[i+1][nxt][S|status] += dp[i][j][S]) %= mod; } long long ans = 0; for(int j=0;j<ac.L;j++) (ans += dp[L][j][(1<<n)-1]) %= mod; printf("%lld\n", ans); }}
- HDU 6086 Rikka with String (AC 自动机+状压 dp, 2017 Multi-Univ Training Contest 5)
- HDU 6085 Rikka with Candies (bitset, 2017 Multi-Univ Training Contest 5)
- HDU 6090 Rikka with Graph (贪心+构造, 2017 Multi-Univ Training Contest 5)
- HDU 6093 Rikka with Number (2017 Multi-Univ Training Contest 5)
- hdu 6086 -- Rikka with String(AC自动机 + 状压DP)
- HDU 6125 Free from square (状压 dp , 2017 Multi-Univ Training Contest 7)
- hdu 6086 Rikka with String ac自动机+dp
- Hdu-6086 Rikka with String(AC自动机+DP)
- HDU 6086 Rikka with String(2017 Multi-University Training Contest 3)
- HDU 6078 Wavel Sequence (dp + 树状数组, 2017 Multi-Univ Training Contest 4)
- HDU 6076 Security Check (DP, 2017 Multi-Univ Training Contest 4)
- HDU 6096 String (字典树, 2017 Multi-Univ Training Contest 6)
- HDU 6093 Rikka with Number (2017 Multi-University Training Contest
- 2017多校赛 1002 Rikka with String(AC自动机+状压)
- 2017 Multi-University Training Contest 5 &&HDU 6085 Rikka with Candies 【bitset+思维】
- HDU 6058 Kanade's sum (链表, 2017 Multi-Univ Training Contest 3)
- HDU 6065 RXD, tree and sequence (LCA, 2017 Multi-Univ Training Contest 3)
- HDU 6071 Lazy Running (Dijstra, 2017 Multi-Univ Training Contest 4)
- 数据库软删除
- 不用加号两数求和
- fileReader对象的事件先后顺序
- HDU4417_树状数组加离线
- 最短路径总结
- HDU 6086 Rikka with String (AC 自动机+状压 dp, 2017 Multi-Univ Training Contest 5)
- Java代码实际执行顺序
- 在vector里存储特殊的结构题,并且支持find函数查找
- 数据库mariadb
- 那些java集合里犯的错
- Codeforces 505B
- Android Studio报Unsupported major.minor version 52.0错误
- C#中volatile的用法
- 第七章 变量进阶和点阵LED