题意
分析
题意容易转化成求循环之后不包含 的串的个数。
首先建立 AC 自动机。考虑一个暴力的做法:枚举长度为 的字符串 最终(后缀) 和 的匹配长度是多少 ()。
这样在开始的时候,我们再记录一维从 的第 个位置开始匹配且没有匹配到 的方案数。
最终状态: 表示 的后缀和 的匹配长度,考虑到了 的第 个字符,在 AC 自动机上从第一个位置出发到达的节点,在 AC 自动机上从第 个位置出发到达的节点。
总时间复杂度为 。
代码
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long LL;
- #define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
- #define rep(i, a, b) for(int i = a; i <= b; ++i)
- #define pb push_back
- #define re(x) memset(x, 0, sizeof x)
- inline int gi() {
- int x = 0,f = 1;
- char ch = getchar();
- while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
- while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
- return x * f;
- }
- template <typename T> inline void Max(T &a, T b){if(a < b) a = b;}
- template <typename T> inline void Min(T &a, T b){if(a > b) a = b;}
- const int N = 44;
- int n, m;
- int ch[N][2], fail[N];
- LL f[N][N][N], ans;
- char s[N];
- int main() {
- n = gi();
- scanf("%s", s + 1);
- m = strlen(s + 1);
- rep(i, 1, m) ch[i - 1][s[i] - '0'] = i;
- rep(i, 1, m)
- rep(j, 0, 1)
- if(ch[i][j]) fail[ch[i][j]] = ch[fail[i]][j];
- else ch[i][j] = ch[fail[i]][j];
- ans = 1ll << n;
- rep(i, 0, m - 1) {
- memset(f, 0, sizeof f);
- f[0][0][i] = 1;
- rep(j, 0, n - 1)rep(k, 0, m - 1)rep(l, 0, m - 1)
- rep(c, 0, 1){
- int a = ch[k][c], b = ch[l][c];
- if(a == m || b == m) continue;
- f[j + 1][a][b] += f[j][k][l];
- }
- rep(j, 0, m - 1)
- ans -= f[n][i][j];
- }
- printf("%lld\n", ans);
- return 0;
- }