[AtCoder Grand Contest 020 Problem E]Encoding Subsets(dp+记忆化搜索)

Address

https://agc020.contest.atcoder.jp/tasks/agc020_e

Solution

如果只是求 S 的编码方案数,那么这是一个简单的区间 DP 问题。
f [ l ] [ r ] 表示子串 [ l , r ] 的编码方案数。
g [ l ] [ r ] 表示子串 [ l , r ] 不可分割的编码方案数。
不可分割是指,子串 [ l , r ] 要么长度为 1 ,要么被编码成 (PxK) 的形式。
容易得出边界 f [ i ] [ i ] = g [ i ] [ i ] = 1 ,转移:

f [ l ] [ r ] = g [ l ] [ r ] + i = l r 1 g [ l ] [ i ] × f [ i + 1 ] [ r ]

g [ l ] [ r ] = d | ( r l + 1 ) 1 d < r l + 1 f [ l ] [ l + d 1 ]

最后答案 f [ 1 ] [ n ]
但题目要求的是 S 的所有子集的方案数之和。
因此稍微改一下状态: f [ S ] g [ S ] 表示 01 串 S 的子集 ^&##&**&# 方案数。
边界: g [ 1 ] = 01 , f [ ] = 1
转移:
f [ S ] = T S T g [ T ] × f [ S T ]

g [ S ] = T S T S f [ T ]

最后答案 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;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81006585