zoukankan      html  css  js  c++  java
  • 雅礼集训【Day6-1】字符串

    雅礼集训【Day6-1】字符串

    img

    假设我们有串(a),我们设(a')(a)翻转后按为取反过后的串。

    我们只考虑前一半的,长为(m)的串。如果前半截匹配了(a)或者(a'),则(a)就被匹配上了。所以我们记(f_{i,j,S})表示长度(i),在AC自动机上匹配到了(j)节点,已经匹配了的串的集合为(S)的方案数。

    但是可能会出现(a)出现的位置跨越了(m),这样我们就会出问题。因为我们记录了生成的串在AC自动机上匹配的节点,所以我们就能得到(a)在前半截中匹配的长度。如果这个长度(geqlfloor frac{len}{2} floor),则我们能知道后半截是什么,也就能判断是否合法了。

    那如果(a)没有匹配长度(geqlfloor frac{len}{2} floor)的情况呢?我们发现,此时(a')的匹配长度一定(geqlfloor frac{len}{2} floor),所以我们同时判断(a)(a'),其中一个成立就行了。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 2005
    #define M 505
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    const ll mod=998244353;
    int n,m;
    string str[20];
    struct trie {
    	int ch[2];
    	int w;
    	int fail;
    	int flag;
    	int len;
    }tr[N];
    
    int rt=1;
    int cnt=1;
    void Insert(string s,int id) {
    	int len=s.length();
    	int v=1;
    	for(int i=0;i<len;i++) {
    		int j=s[i]-'0';
    		if(!tr[v].ch[j]) {
    			tr[v].ch[j]=++cnt;
    			tr[tr[v].ch[j]].len=tr[v].len+1;
    		}
    		v=tr[v].ch[j];
    	}
    	tr[v].w|=1<<id-1;
    }
    
    queue<int>q;
    void build_fail() {
    	for(int i=0;i<2;i++) {
    		if(!tr[1].ch[i]) tr[1].ch[i]=1;
    		else {
    			int x=tr[1].ch[i];
    			tr[x].fail=1;
    			q.push(x);
    		}
    	}
    	while(!q.empty()) {
    		int v=q.front();
    		q.pop();
    		tr[v].w|=tr[tr[v].fail].w;
    		for(int i=0;i<2;i++) {
    			if(!tr[v].ch[i]) tr[v].ch[i]=tr[tr[v].fail].ch[i];
    			else {
    				int sn=tr[v].ch[i];
    				int f=tr[v].fail;
    				tr[sn].fail=tr[f].ch[i];
    				q.push(sn);
    			}
    		}
    	}
    }
    int pre[20][N];
    int f[M][1205][1<<6];
    bool pd(string &a,int len,int v,int id) {
    	int now=1;
    	tr[1].flag=1;
    	for(int i=0;i<len;i++) {
    		now=tr[now].ch[a[i]-'0'];
    		tr[now].flag=1;
    	}
    	while(!tr[v].flag) v=tr[v].fail;
    	int nlen=0;
    	now=1;
    	for(int i=0;i<len&&now!=v;i++,nlen++) {
    		now=tr[now].ch[a[i]-'0'];
    	}
    	int flag=0;
    	while(v) {
    		if(tr[v].flag&&pre[id][tr[v].len]) flag=1;
    		v=tr[v].fail;
    	}
    	tr[1].flag=0;
    	now=1;
    	for(int i=0;i<len;i++) {
    		now=tr[now].ch[a[i]-'0'];
    		tr[now].flag=0;
    	}
    	return flag;
    }
    
    bool chk(int v,int S) {
    	for(int i=1;i<=n;i++) {
    		if(S>>i-1&1) continue ;
    		int len=str[i].length();
    		if(!pd(str[i],len,v,i)&&!pd(str[i+n],len,v,i+n)) return 0;
    	}
    	return 1;
    }
    
    int main() {
    	n=Get(),m=Get();
    	for(int i=1;i<=n;i++) cin>>str[i];
    	for(int i=1;i<=n;i++) {
    		int len=str[i].length();
    		for(int j=len-1;j>=0;j--) {
    			str[i+n].push_back(str[i][j]^1);
    		}
    	}
    	for(int i=1;i<=n;i++) {
    		Insert(str[i],i);
    		Insert(str[i+n],i);
    	}
    	build_fail();
    	f[0][1][0]=1;
    	for(int i=0;i<m;i++) {
    		for(int j=1;j<=cnt;j++) {
    			for(int S=0;S<1<<n;S++) {
    				if(!f[i][j][S]) continue ;
    				for(int k=0;k<2;k++) {
    					int to=tr[j].ch[k];
    					(f[i+1][to][S|tr[to].w]+=f[i][j][S])%=mod;
    				}
    			}
    		}
    	}
    	
    	for(int i=1;i<=2*n;i++) {
    		int len=str[i].length();
    		for(int st=1;st<=len;st++) {
    			if(st*2<len) continue ;
    			int flag=1;
    			for(int j=st;j<len;j++) {
    				if(str[i][j]==str[i][2*st-j-1]) flag=0;
    			}
    			pre[i][st]=flag;
    		}
    	}
    	
    	int ans=0;
    	for(int i=1;i<=cnt;i++) {
    		for(int S=0;S<1<<n;S++) {
    			if(!f[m][i][S]) continue ;
    			if(chk(i,S)) {
    				(ans+=f[m][i][S])%=mod;
    			}
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    
    
  • 相关阅读:
    你最喜欢的程序员漫画
    编程名言名句
    查看一个数是不是2的n次方
    程序员需要有多懒 ?- cocos2d-x 数学函数、常用宏粗整理
    C++中string、int、char之间转换
    cocos2d-x 中使用 srand((unsigned)time(NULL))重新设置一个随机种子
    ASP.NET MVC SignalR 配合VUE
    VS Visual Studio光标无法自动到行尾,点哪里就在哪里解决办法
    .NET Core Entity Framework 代码优先配置
    Image Bitmap转MemoryStream后,上传遇到问题,报Index异常
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10616091.html
Copyright © 2011-2022 走看看