这题看上去就有一股乱搞的感觉。
注意到答案显然可以DP,对于一个字符串S SS,我们令F [ S ] F[S]F[S]代表S SS的所有子集的编码方案数之和。那么考虑最左边被编码的是哪个子串,有F [ S ] = ( 1 + [ S 1 = 1 ] ) ⋅ F [ S 2... ∣ s ∣ ] + ∑ i j ≤ n F [ S 1... i a n d S i + 1...2 i a n d . . . S ( j − 1 ) i + 1... i j ] ⋅ F [ S i j + 1... ∣ s ∣ ] F[S]=(1+[S_1=1]) \cdot F[S_{2...|s|}]+\sum_{ij\leq n}F[S_{1...i} \ and \ S_{i+1...2i} \ and \ ... S_{(j-1)i+1...ij}] \cdot F[S_{ij+1...|s|}]F[S]=(1+[S1=1])⋅F[S2...∣s∣]+∑ij≤nF[S1...i and Si+1...2i and ...S(j−1)i+1...ij]⋅F[Sij+1...∣s∣]。
直接对这个DP记忆化就能通过了。题解有高超技巧证明状态数目上界是O ( n 3 + 2 n 8 ) \mathcal O(n^3+2^{\frac{n}{8}})O(n3+28n)的,我用了map<string,int>导致巨慢。
#include <bits/stdc++.h>
#define MOD 998244353
using namespace std;
typedef long long ll;
map <string,int> mp;
void merge(string &x,string y) {
for(int i=0;i<x.length();i++)
if (y[i]=='0') x[i]='0';
}
int dp(string s) {
if (s.empty()) return 1;
if (mp.count(s)) return mp[s];
int n=s.length(),ans=0;
ans=(ans+((s[0]=='1')?2LL:1LL)*dp(s.substr(1,n)))%MOD;
for(int i=1;2*i<=n;i++) {
string cur=s.substr(0,i);
for(int j=2;i*j<=n;j++) {
merge(cur,s.substr(i*(j-1),i*j));
ans=(ans+(ll)dp(cur)*dp(s.substr(i*j,n)))%MOD;
}
}
return mp[s]=ans;
}
int main() {
string s;
cin>>s;
cout<<dp(s)<<endl;
return 0;
}
版权声明:本文为qq_38609262原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。