[atAGC020E]Encoding Subsets

令$f_{S}$表示字符串$S$的答案(所有子集的方案数之和),考虑转移:

1.最后是一个字符串,不妨仅考虑最后一个字符,即$f_{S[1,|S|)}$(字符串下标从1开始),特别的,若$S_{|S|}=1$,还有一个2倍的系数

2.是一个乘法,考虑是$k\times T$,记$l=|T|$,则$T$需要是末尾$k$段长为$l$的串的公共子集,不难发现这个公共子集就是这$k$个串求and后的串$T'$的子集,那么贡献即为$f_{T'}\cdot f_{S[1,|S|-kl]}$

对其记忆化搜索即可,以下来证明状态数:

考虑$f_{S[1,|S|-kl]}$这个状态,一定会通过第一种若干次后得到,因此不需要考虑

接下来,构造一棵搜索树,但这棵搜索树的每一个儿子是父亲的一个长为$kl$的子串($k\ge 2$)的$k$段字符串求and后的结果,$S$为第一层

对于四层即以后的字符串,长度一定不超过$\lfloor\frac{n}{8}\rfloor$,即至多$o(2^{\lfloor\frac{n}{8}\rfloor})$个

对于前三层的字符串,显然只需要统计第三层就足够了

当其中某一层的$k\ge 3$时,那么这一个串长度不超过$\lfloor\frac{n}{6}\rfloor$,类似的总量为$o(2^{\lfloor\frac{n}{6}\rfloor})$,也可以接受

接下来,每一层的$k$都为2,之后假设其父亲长度为$l_{1}$,自己的长度为$l_{2}$,其对应于$S$中,即$S$中的4个长为$l_{2}$的串的and,且第1和2个串相连、第3和4个串相连

因此这个字符串仅取决于第一个起点、第二个起点以及串长,总量为$o(n^{3})$

总复杂度约为$o(2^{\lfloor\frac{n}{6}\rfloor}+n^{3})$,实际上分析仍有很大的改善空间,即跑不满

具体记忆化的实现哈希+map即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 105
 4 #define mod 998244353
 5 map<int,int>f[N];
 6 char s[N];
 7 int get_hash(int l,char *s){
 8     int ans=0;
 9     for(int i=0;i<l;i++)ans=(3LL*ans+s[i]-'0')%mod;
10     return ans;
11 }
12 int dfs(int l,char *s){
13     if (!l)return 1;
14     int h=get_hash(l,s);
15     if (f[l][h])return f[l][h];
16     int ans=(1+s[l-1]-'0')*dfs(l-1,s)%mod;
17     char t[N];
18     for(int i=1;i<=l/2;i++){
19         for(int k=0;k<i;k++)t[k]=s[l-i+k];
20         for(int j=2;i*j<=l;j++){
21             for(int k=0;k<i;k++)t[k]=min(t[k],s[l-i*j+k]);
22             ans=(ans+1LL*dfs(l-i*j,s)*dfs(i,t))%mod;
23         }
24     }
25     return f[l][h]=ans;
26 }
27 int main(){
28     scanf("%s",s);
29     printf("%d",dfs(strlen(s),s));
30 }
View Code

 

posted @ 2021-02-04 14:21  PYWBKTDA  阅读(65)  评论(0编辑  收藏  举报