HDU 6086 Rikka with String(AC 자동기+상압 dp, 2017 Multi-Univ Training Contest 5)
10714 단어 HDUMulti-Univ
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열 si에 대해 2L의 반회문 문자열 (antisymmeric strings) 을 구하여 n개의 문자열이 모두 하위 문자열로 나타났다.
그 중에서 반회문 직렬 s가si≠s|s||-3i+1을 만족시킨다
Limit
1≤n≤6
1≤L≤100
1≤∣si∣≤20
Idea
만약 반환문열의 문제를 고려하지 않는다면, 이 문제는 간단한 AC자동기 + dp (물론 상압이 필요하다) 의 문제이다.이해할 수 없으면 직접 검색하십시오.
반회문의 설정이 있기 때문에 2L 길이의 01열에 대해 현재 L 길이가 알려졌을 때 이후 L 길이는 반드시 확정된다.그러므로 세 가지 상황을 고려하면 문자열 si는 앞 L에 있고 뒤 L 또는 일부는 앞 L 부분에서 뒤 L에 있다.
jugGapAndInsert()
함수)에 완전하게 나타나게 하고 이를 AC자동기에 가입시킬 수 있다.AC 자동기는 fail 포인터를 생성한 후 dp를 직접 상압한다.
Code
#include
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;i1;
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;iif(nxt[p][buf[i]] == -1)
nxt[p][buf[i]] = newnode();
p = nxt[p][buf[i]];
}
if(flg) isEnd[p] |= (1<else end[p] |= (1<1<void build() {
queue<int> que;
fail[root] = root;
for(int i=0;iif(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;iif(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("]
");
}
}
}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;i1;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;iscanf(" %s", s[i]);
len = strlen(s[i]);
for(int j=0;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;j1;j++)
jugGapAndInsert(i, j);
}
ac.build();
//ac.debug();
dp[0][0][0] = 1;
for(int i=0, nxt, tmpNxt, status, isEnd;ifor(int j=0;jfor(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;S1<1][nxt][S|status] += dp[i][j][S]) %= mod;
}
long long ans = 0;
for(int j=0;j1<1]) %= mod;
printf("%lld
", ans);
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
hdu4671(다교리그 7--수 시뮬레이션)클릭하여 링크 열기 제목: n과 서버, m개의 데이터베이스가 있고 모든 데이터베이스는 서버를 연결해야 하지만 모든 데이터베이스는 서버를 연결하는 우선순위가 있습니다.모든 데이터베이스의 서버 우선순위를 구하다.또한 한...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.