Address
https://agc020.contest.atcoder.jp/tasks/agc020_e
Solution
如果只是求
S
S
的编码方案数,那么这是一个简单的区间 DP 问题。
表示子串
[l,r]
[
l
,
r
]
的编码方案数。
g[l][r]
g
[
l
]
[
r
]
表示子串
[l,r]
[
l
,
r
]
的不可分割的编码方案数。
不可分割是指,子串
[l,r]
[
l
,
r
]
要么长度为
1
1
,要么被编码成 (PxK) 的形式。
容易得出边界 ,转移:
最后答案 f[1][n] f [ 1 ] [ n ] 。
但题目要求的是 S S 的所有子集的方案数之和。
因此稍微改一下状态: 和 g[S] g [ S ] 表示 01 串 S S 的子集 ^&##&**&# 方案数。
边界:
转移:
最后答案 f[原串] f [ 原 串 ] 。
Code
#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int PYZ = 998244353;
map<string, int> f, g;
int F(string); int G(string);
int G(string s) {
if (g[s]) return g[s]; int i, n = s.size(); if (n == 1) return g[s] = s[0] - '0' + 1;
int j, k, res = 0; For (i, 1, n - 1) if (n % i == 0) {
string t = ""; For (j, 1, i) {
int r = 1; Step (k, j - 1, n - 1, i) r &= s[k] - '0';
t += (char) (r + '0');
}
res = (res + F(t)) % PYZ;
}
return g[s] = res;
}
int F(string s) {
if (f[s]) return f[s]; int i, n = s.size(); if (!n) return f[s] = 1;
int res = 0; For (i, 1, n)
res = (res + 1ll * G(s.substr(0, i)) * F(s.substr(i, n)) % PYZ) % PYZ;
return f[s] = res;
}
int main() {
string s; cin >> s; cout << F(s) << endl;
return 0;
}