题目链接:868D - Huge Strings
题目大意:有\(n\)个字符串,\(m\)次操作,每次操作把两个字符串拼在一起,并询问这个新串的价值。定义一个新串的价值\(k\)为:最大的\(k\),使得这个新串包含所有长度为\(k\)的01串(这样的字符串有\(2^k\)个)
题解:首先来证明对于任何的串,这个\(k\)的值不会超过9
若\(k=10\),由所有字符串的长度总和不超过100,因此在初始的\(n\)个串里,互不相同的长度为\(k\)的子串不超过100个。又由于每次连接最多能产生9个新的长度为\(k\)的子串(即横跨两个字符串之间的子串),因此互不相同的子串个数最多为\(9 \cdot100+100<2^k\),故\(k<10\)
接下来就只需要记录每个字符串的前缀,后缀以及长度为\(k\)的子串有哪些就好了。
#include<bits/stdc++.h> using namespace std; #define N 101 int n,m,a,b; struct rua { string st,ed; set<int>has[10]; bool check(int k) { for(int i=0;i<(1<<k);i++) if(!has[k].count(i))return false; return true; } int ans() { for(int k=9;k>0;k--) if(check(k))return k; return 0; } rua connect(rua nxt) { rua res=nxt; res.st=st; if(st.size()<9) res.st=st+nxt.st.substr(0,min(nxt.st.size(),9-st.size())); int cpy_len=min(ed.size(),9-nxt.ed.size()); if(nxt.ed.size()<9) res.ed=ed.substr(ed.size()-cpy_len,cpy_len)+nxt.ed; for(int k=1;k<=9;k++) for(auto i:has[k])res.has[k].insert(i); string tmp=ed+nxt.st; int len=tmp.size(); for(int i=0;i<len;i++) { int value=0; for(int d=0;d<9 && i+d<len;d++) value=value*2+tmp[i+d]-‘0‘, res.has[d+1].insert(value); } return res; } }f[2*N]; string s; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { cin>>s; int len=s.size(); for(int j=0;j<len;j++) { int value=0; for(int d=0;d<9 && j+d<len;d++) value=value*2+s[j+d]-‘0‘, f[i].has[d+1].insert(value); } int cpy_len=min(9,len); f[i].st=s.substr(0,cpy_len); f[i].ed=s.substr(len-cpy_len,cpy_len); } scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); f[n+i]=f[a].connect(f[b]); printf("%d\n",f[n+i].ans()); } }
原文地址:https://www.cnblogs.com/DeaphetS/p/9693580.html
时间: 2024-10-09 21:37:05