CF 827E - Rusty String FFT 字符串 循环节

题意:

给你一个字符串,只含'V', 'K', '?',其中'?’可能是任意这两个字符之一,问可能的循环节?(循环节不用整除N,只要满足s[i] = s[i + k])

题解:

找循环节,就是找所有公共前后缀长度。

现在有'?’ ,属于模糊匹配, 只能用FFT。

(s[i] - t[i]) ^2 * s[i] * t[i]等于0的话就可以匹配,拆开是s[i]^3t[i] - 2 * s[i] * t[i] + s[i]t[i]^3,做三次FFT即可。

(貌似不用做三次,别人都是做一次,我的做法常数比较大,贴一个别人的博客:

https://blog.csdn.net/v5zsq/article/details/79058756

但是问题还没这么简单,

样例给出了一个反例。

5
V??VK

本来这组我们会算出有长度为2的循环节,但是不对。

v??能和 ?vk匹配,这是肯定的,但为什么不行呢?

注意到原串中间的那个?,既要等于V,又要等于K,这样就出矛盾了,所以不行。

 抽象一下,其实问题在于:

有些?会匹配两个不同的字符。

什么时候会出现这样的情况?

当匹配的前后缀交叉的时候,中间的?假设下标为i,循环节长度为k,那么s[i] = s[i + k] , s[i - k] = s[i]。这时应该满足s[i] = s[i + 2k]才行,而且这本来就是循环节所应该满足的性质。

然而光判断2k是否是循环节这样还是有问题,再抽象一下,应该是判断所有k的倍数是否为循环节才行。

为什么?

中间的这些圆点应该都相同才行。

所以这题就这样啦。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <cmath>
#include <ctime>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif

#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pii;

const ll MOD = 1e9 + 7;
const double PI = acos (-1.);
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 262144 * 8 + 5;

char s[MAXN];
char t[MAXN];

//typedef complex<double> CP;
struct CP {
    double x, y;
    CP() {}
    CP (double x, double y) : x (x), y (y) {}
    inline double real() {
        return x;
    }
    inline CP operator * (const CP& r) const {
        return CP (x * r.x - y * r.y, x * r.y + y * r.x);
    }
    inline CP operator - (const CP& r) const {
        return CP (x - r.x, y - r.y);
    }
    inline CP operator + (const CP& r) const {
        return CP (x + r.x, y + r.y);
    }
    inline CP conj (const CP &r) {
        return CP (r.x, -r.y);
    }
};
CP a[MAXN], b[MAXN];
int r[MAXN], res[MAXN];
void fft_init (int nm, int k) {
    for (int i = 0; i < nm; ++i) r[i] = (r[i >> 1] >> 1) | ( (i & 1) << (k - 1) );
}
void fft (CP ax[], int nm, int op) {
    for (int i = 0; i < nm; ++i) if (i < r[i]) swap (ax[i], ax[r[i]]);
    for (int h = 2, m = 1; h <= nm; h <<= 1, m <<= 1) { // 枚举长度
        CP wn = CP (cos (op * 2 * PI / h), sin (op * 2 * PI / h) );
        for (int i = 0; i < nm; i += h) { // 枚举所有长度为 h 的区间
            CP w (1, 0); // 旋转因子
            for (int j = i; j < i + m; ++j, w = w * wn) { // 枚举角度
                CP t = w * ax[j + m]; // 蝴蝶操作
                ax[j + m] = ax[j] - t;
                ax[j] = ax[j] + t;
            }
        }
    }
    if (op == -1) for (int i = 0; i < nm; ++i) ax[i].x /= nm;
}
void trans (int ax[], int bx[], int n, int m, int mul) {
    int nm = 1, k = 0;
    while (nm < 2 * n || nm < 2 * m) nm <<= 1, ++k;
    for (int i = 0; i < n; ++i) a[i] = CP (ax[i], 0);
    for (int i = 0; i < m; ++i) b[i] = CP (bx[i], 0);
    for (int i = n; i < nm; ++i) a[i] = CP (0, 0);
    for (int i = m; i < nm; ++i) b[i] = CP (0, 0);
    fft_init (nm, k);
    fft (a, nm, 1);
    fft (b, nm, 1);
    for (int i = 0; i < nm; ++i) a[i] = a[i] * b[i];
    fft (a, nm, -1);
    nm = n + m - 1;
    for (int i = 0; i < nm; ++i) res[i] += (int) (a[i].real() + 0.5) * mul;
}

int s1[MAXN], t1[MAXN];
int ans[MAXN];

int getid (char x) {
    if (x == 'V') return 1;
    if (x == 'K') return -1;
    return 0;
}

int main() {
#ifdef LOCAL
    freopen ("input.txt", "r", stdin);
#endif
    int T;
    cin >> T;
    while (T--) {
        int n;
        scanf ("%d %s", &n, s);
        for (int i = 0; i <= 2 * n; i++) res[i] = 0;
        for (int i = 0; i < n; i++) {
            s1[i] = getid (s[i]) * getid (s[i]) * getid (s[i]);
            t1[i] = getid (s[i]);
        }
        reverse (t1, t1 + n);
        trans (s1, t1, n, n, 1);
        for (int i = 0; i < n; i++) {
            s1[i] = getid (s[i]);
            t1[i] = getid (s[i]) * getid (s[i]) * getid (s[i]);
        }
        reverse (t1, t1 + n);
        trans (s1, t1, n, n, 1);
        for (int i = 0; i < n; i++) {
            s1[i] = getid (s[i]) * getid (s[i]);
            t1[i] = getid (s[i]) * getid (s[i]);
        }
        reverse (t1, t1 + n);
        trans (s1, t1, n, n, -2);
        for (int i = 0; i <= n; i++) ans[i] = 0;
        for (int i = 0; i < n; i++)
            if (res[i] == 0) ans[n - i - 1] = 1;

        ans[n] = 1;
        vector<int> v;
        for (int i = n; i >= 1; i--) {
            for (int j = i + i; j <= n; j += i) ans[i] &= ans[j];
            if (ans[i]) v.pb (i);
        }
        printf ("%d\n", v.size() );
        reverse (v.begin(), v.end() );
        for (int i : v) printf ("%d ", i);
        puts ("");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/c6376315qqso/article/details/82793991
今日推荐