【BZOJ4560】[JLoi2016]字符串覆盖 KMP+状压DP
【BZOJ4560】[JLoi2016]字符串覆盖
Description
字符串A有N个子串B1,B2,…,Bn。如果将这n个子串分别放在恰好一个它在A中出现的位置上(子串之间可以重叠)这样A中的若干字符就被这N个子串覆盖了。问A中能被覆盖字符个数的最小值和最大值。
Input
第一行包含一个正整数T,表示数据组数。保证T≤10。接下来依次描述T组数据,每组数据中:第一行包含一个由小写字母组成的字符串,表示母串A。第二行包含一个整数N,表示子串的个数。接下来N行,每行包含一个由小写字母组成的字符串,描述子串。数据保证所有子串均在母串中出现。字符串长度A<=10000,N<=4,子串长充<=1000
Output
输出为T行,对应每组数据的答案。每行包含两个整数Minans和Maxans,分别表示对应数据中能被覆盖字符数量的最小值和最大值。
Sample Input
2
hello
4
he
l
l
o
abacaba
4
ab
ba
a
c
hello
4
he
l
l
o
abacaba
4
ab
ba
a
c
Sample Output
4 5
4 6
4 6
题解:网上题解说是某贪心?然而我只会状压DP。
先用KMP求出每个子串的所有出现位置,然后用f[i][j]表示前i个字符,子串的出现情况为j的覆盖数量最大值,g[i][j]表示最小值。转移时需要用到树状数组。
然而状压的做法似乎好多情况都无法处理,如子串存在包含的情况。。。总之加了一坨特判就过了,可能会被hack。
代码不可读。
#include <cstdio> #include <cstring> #include <iostream> #define lson x<<1 #define rson x<<1|1 using namespace std; const int maxn=10010; int n,m; int len[5],vis[5],ch[maxn],next[maxn]; char S[maxn],T[5][maxn]; int f[maxn][16],g[maxn][16],sf[maxn][16],sg[maxn][16]; struct node { int s[maxn],typ; inline int cmp(int a,int b) { return ((a>b)^typ)?a:b; } inline void updata(int x,int v) { x++; for(int i=x;i;i-=i&-i) s[i]=cmp(s[i],v); } inline int query(int x) { x++; int i,ret=s[0]; for(i=x;i<=m+1;i+=i&-i) ret=cmp(ret,s[i]); return ret; } }s1[16],s2[16]; void work() { scanf("%s",S),m=strlen(S); scanf("%d",&n); int i,j,k,a,b,tmp=(1<<n)-1; memset(ch,0,sizeof(ch)); for(i=1;i<=n;i++) { memset(next,0,sizeof(next)); scanf("%s",T[i]),len[i]=strlen(T[i]); next[0]=k=-1,j=0; while(j<len[i]) { if(k==-1||T[i][j]==T[i][k]) next[++j]=++k; else k=next[k]; } j=k=0; while(j<m) { if(k==-1||S[j]==T[i][k]) j++,k++; else k=next[k]; if(k==len[i]) ch[j-len[i]]|=1<<(i-1); } } memset(vis,0,sizeof(vis)); for(a=1;a<=n;a++) for(b=1;b<=n;b++) if(a!=b&&!vis[a]&&!vis[b]) { memset(next,0,sizeof(next)); next[0]=k=-1,j=0; while(j<len[a]) { if(k==-1||T[a][j]==T[a][k]) next[++j]=++k; else k=next[k]; } j=k=0; while(j<len[b]) { if(k==-1||T[b][j]==T[a][k]) j++,k++; else k=next[k]; if(k==len[a]) { vis[a]=1; break; } } } for(i=1;i<=n;i++) if(vis[i]) tmp^=1<<(i-1); memset(s1,0xc0,sizeof(s1)),memset(s2,0x3f,sizeof(s2)); memset(sf,0xc0,sizeof(sf)),memset(sg,0x3f,sizeof(sg)); memset(f,0xc0,sizeof(f)),memset(g,0x3f,sizeof(g)); for(i=0;i<1<<n;i++) s1[i].typ=0,s2[i].typ=1,f[0][i]=-1<<30,g[0][i]=1<<30; for(i=0;i<=m;i++) { for(j=0;j<1<<n;j++) { if(!i) { if(!j) f[0][0]=g[0][0]=sf[0][0]=sg[0][0]=0; else f[0][j]=s1[j].query(i)+i,g[0][j]=s2[j].query(i)+i; } else { sf[i][j]=max(sf[i][j],sf[i-1][j]),sg[i][j]=min(sg[i][j],sg[i-1][j]); f[i][j]=max(sf[i][j],s1[j].query(i)+i),g[i][j]=min(sg[i][j],s2[j].query(i)+i); } for(k=1;k<=n;k++) if(!((j>>(k-1))&1)&&((ch[i]>>(k-1))&1)) { s1[j|(1<<(k-1))].updata(i+len[k],f[i][j]-i); sf[i+len[k]][j|(1<<(k-1))]=max(sf[i+len[k]][j|(1<<(k-1))],f[i][j]+len[k]); if(!vis[k]) { s2[j|(1<<(k-1))].updata(i+len[k],g[i][j]-i); sg[i+len[k]][j|(1<<(k-1))]=min(sg[i+len[k]][j|(1<<(k-1))],g[i][j]+len[k]); } } } } int ans=0; for(i=1;i<1<<n;i++) if((i&tmp)==tmp) ans=max(ans,f[m][i]); printf("%d %d\n",g[m][tmp],ans); } int main() { int T; scanf("%d",&T); while(T--) work(); return 0; }//2 hello 4 he l l o abacaba 4 ab ba a c
| 欢迎来原网站坐坐! >原文链接<