2016NA邀请赛-E - K-Inversions-FFT简单题

题目大意:

给你一个只含 A , B A,B A,B的字符串.问你有多少个间隔为 k k k的字符对满足前一个是 B B B.后一个是 A A A.

题目思路:

发现又是这种只有两种的字符的.显然我们可以直接将字符串当成多项式乘起来.

对于一个 k k k,我们就是要求: ∑ i = 0 n − k − 1 [ s i = = B & & s i + k = A ] \sum_{i=0}^{n-k-1}[s_i==B\&\&s_{i+k}=A] i=0nk1[si==B&&si+k=A]

长得有点像卷积,我们对前者,将 B B B置为1. A A A置为0. 对于后者,翻转序列,对 A A A置1. B B B置0.

上述式子就变成了: ∑ i = 0 n − k − 1 s i ∗ t n − k − 1 − i \sum_{i=0}^{n-k-1}s_i*t_{n-k-1-i} i=0nk1sitnk1i.这不就变成卷积了.直接套板子完事.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
namespace NTT
{
    
    
    const int P=998244353,g=3;
    const int W=22,S=1<<W;
    const int J=86583718;

    inline int add(int a,int b) {
    
    int r=a+b; return r<P?r:r-P;}
    inline int sub(int a,int b) {
    
    int r=a-b; return r<0?r+P:r;}
    inline int mul(long long a,long long b) {
    
    return (a*b)%P;}
    inline int inv(int a) {
    
    return a==1?a:mul(inv(P%a),P-P/a);}
    inline int qpow(int a,long long k)
    {
    
    
        int r=1;
        while (k)
        {
    
    
            if (k&1) r=mul(r,a);
            k>>=1; a=mul(a,a);
        }
        return r;
    }

    const int i2=inv(2),ij=inv(J);

    int r[S],w[2][S];
    void init(int lim)
    {
    
    
        int w0=qpow(g,(P-1)/lim);
        w[0][0]=w[1][0]=1;
        for (int i=1;i<lim;i++) w[0][i]=w[1][lim-i]=mul(w[0][i-1],w0);
        for (int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)*(lim>>1));
    }

    void ntt(int *a,int lim,int o)
    {
    
    
        for (int i=0;i<lim;i++) if (i<r[i]) swap(a[i],a[r[i]]);
        for (int i=1;i<lim;i<<=1)
        {
    
    
            for (int j=0,t=lim/(i<<1);j<lim;j+=i<<1)
            {
    
    
                for (int k=j,l=0;k<j+i;k++,l+=t)
                {
    
    
                    int x=a[k],y=mul(w[o][l],a[k+i]);
                    a[k]=add(x,y);
                    a[k+i]=sub(x,y);
                }
            }
        }
        if (o)
        {
    
    
            int tmp=NTT::inv(lim);
            for (int i=0;i<lim;i++) a[i]=mul(a[i],tmp);
        }
    }

    int p1[S],p2[S];
    vector<int>poly_mul(const vector<int>&a,const vector<int>&b)
    {
    
    
        int n=a.size(),m=b.size();
        int lim=1;
        while (lim<(n<<1)) lim<<=1;
        while (lim<(m<<1)) lim<<=1;
        init(lim);
        copy_n(a.begin(),n,p1); fill(p1+n,p1+lim,0);
        copy_n(b.begin(),m,p2); fill(p2+m,p2+lim,0);
        ntt(p1,lim,0);
        ntt(p2,lim,0);
        for (int i=0;i<lim;i++) p1[i]=mul(p1[i],p2[i]);
        ntt(p1,lim,1);
        return vector<int>(p1,p1+n+m-1);
    }
    void f_poly_mul(int a[] , int b[] , int n , int m , int res[])
    {
    
    
        int lim=1;
        while (lim<(n<<1)) lim<<=1;
        while (lim<(m<<1)) lim<<=1;
        init(lim);
        memcpy(p1 , a , sizeof(int) * n);fill(p1+n,p1+lim,0);
        memcpy(p2 , b , sizeof(int) * m);fill(p2+m,p2+lim,0);
        ntt(p1,lim,0);
        ntt(p2,lim,0);
        for (int i=0;i<lim;i++) p1[i]=mul(p1[i],p2[i]);
        ntt(p1,lim,1);
        for (int i = 0 ; i < n + m ; i++) res[i] = p1[i];
        return ;
    }
}
int st[maxn] , ss[maxn] , fa[maxn] , fb[maxn] , res[maxn];
char a[maxn] , b[maxn];
int main()
{
    
    
    scanf("%s" , a);
    memcpy(b , a , sizeof a);
    int n = strlen(a);
    reverse(b , b + n);
    for (int i = 0 ; i < n ; i++) fa[i] = a[i] - 'A';
    for (int i = 0 ; i < n ; i++) fb[i] = !(b[i] - 'A');
    NTT::f_poly_mul(fa , fb , n , n , res);
    for (int i = 1 ; i < n ; i++) printf("%d\n" , res[n - i - 1]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/115080807