首先先考虑如果没有什么子集的限制怎样计算方案数。明显就是一个区间 \(dp\),这个恰好一年前就做过类似的题目了。我们设 \(f_{l,r}\) 为压缩 \([l,r]\) 的方案数,\(g_{l,r}\) 表示压缩 \([l,r]\),并且强制要求 \([l,r]\) 必须用括号括起来的方案数,那么 \(f_{l,r}\) 转移显然可以枚举第一段括号的位置,即 \(f_{l,r}=\sum\limits_{k=l-1}^rg_{l,k}f_{k+1,r}\)。\(g_{l,r}\) 转移就枚举循环节长度 \(len\),即 \(g_{l,r}=\sum f_{l,l+len-1}[len\ \text{为}\ s[l...r]\ \text{的循环节}]\)。
接下来考虑加上“子集”这个条件之后怎样计算答案,还是设 \(f_{l,r}\) 表示将 \([l,r]\) 所有子集压缩的方案数之和,\(g_{l,r}\) 表示将 \([l,r]\) 所有子集压缩,并且强制要求 \([l,r]\) 必须用括号括起来的方案数。显然 \(f\) 还是一样的转移方式,算 \(g\) 的时候就有些不同了,我们枚举 \(r-l+1\) 的所有约数 \(len\),并考虑 \(s[l...r]\) 中每一段长度为 \(len\) 的字符串,即 \(s[l...l+len-1],s[l+len...l+2len-1]\dots\),我们将这 \(\dfrac{r-l+1}{len}\) 个字符串每一位 AND 起来,然后求它的 \(f\) 值就行了,可以用记忆化搜索实现。
这个算法复杂度看起来不太对。但这只是看起来,事实上这样写即可通过此题。我们粗略估计一下可得 \(T(n)=\sum\limits_{i=1}^n(n-i+1)(\sum\limits_{d\mid i}(i+T(\dfrac{i}{d})))\),稍微打个表即可发现这个 \(T(n)\) 并不会特别大,因此这样写是没问题的。
这题告诉我们看到 \(n\le 100\) 不要习惯性地想 \(n^4\) 或 \(n^3\log n\),有的复杂度奇怪的解法也可以通过这种小数据。
#include <bits/stdc++.h> using namespace std; #define fi first #define se second #define fill0(a) memset(a,0,sizeof(a)) #define fill1(a) memset(a,-1,sizeof(a)) #define fillbig(a) memset(a,63,sizeof(a)) #define pb push_back #define ppb pop_back #define mp make_pair template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;} template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;} typedef pair<int,int> pii; typedef long long ll; typedef unsigned int u32; typedef unsigned long long u64; namespace fastio{ #define FILE_SIZE 1<<23 char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf; inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;} inline void putc(char x){(*p3++=x);} template<typename T> void read(T &x){ x=0;char c=getchar();T neg=0; while(!isdigit(c)) neg|=!(c^'-'),c=getchar(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); if(neg) x=(~x)+1; } template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);} template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);} void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);} } const int MOD=998244353; map<string,int> f,g; string s; int calcg(string s); int calcf(string s){ if(s==""||s=="0") return 1; if(s=="1") return 2; if(f.count(s)) return f[s]; int ret=0;for(int i=1;i<=s.size();i++){ string s1,s2; for(int j=0;j<i;j++) s1+=s[j]; for(int j=i;j<s.size();j++) s2+=s[j]; ret=(ret+1ll*calcg(s1)*calcf(s2))%MOD; } return f[s]=ret; } int calcg(string s){ if(s==""||s=="0") return 1; if(s=="1") return 2; if(g.count(s)) return g[s]; int ret=0; for(int i=1;i<s.size();i++){ if(s.size()%i) continue;string t=""; for(int j=0;j<i;j++){ int flg=1; for(int k=j;k<s.size();k+=i) flg&=(s[k]-'0'); t+=(flg^48); } ret=(ret+calcf(t))%MOD; } return g[s]=ret; } int main(){ cin>>s;printf("%d\n",calcf(s)); return 0; }