挺有价值的 (dp) 题。
设 (f[i][j]) 是 (01) 串的前 (i) 位构成的子串形成了 (j) 这个数的可能性数量。
对 (i) 进行倒序枚举,可以得到 (dp) 方程 :
[f[i][j] = f[i][j] + f[k-1][j-tmp]
]
其中 (1le k le i,1 le i le n, 1 le j le m)。(tmp) 为剩下的部分组成的数 。
最后的答案就是 (sumlimits_{i=1}^mf[n][i]) 。
记得取膜。。。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 998244353;
const int N = 3010;
ll n, m;
char ch[N];
ll f[N][N];//f[i][j]表示01串用前i位构成的j这个数有几种可能
int main() {
cin >> m;
cin >> ch + 1;
n = strlen(ch + 1);
f[0][0] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
int tmp = 0;
for(int k = i; k >= 1; k--) {
if(ch[k] == '0') continue;
else tmp += (1 << (i - k));//对j这个数进行拆分
if(tmp > j) break;
else {
f[i][j] += f[k-1][j-tmp];//少一位,枚举这一位
f[i][j] %= mod;
}
}
}
}
ll ans = 0;
for(int i = 1; i <= m; i++) ans = (ans + f[n][i]) % mod;
printf("%lld
",ans * 2 % mod);
return 0;
}