fft/ntt

来源:互联网 发布:淘宝店铺怎么免费上货 编辑:程序博客网 时间:2024/03/29 09:55

cf827E
cf773E
cf662C
cf632E
cf623E
cf553E
cf528D
cf472G
cf438E
cf300D
cf286E

bzoj3160
题意:在一个仅仅含有a,b的字符串里选取一个子序列,使得:
1.位置和字符都关于某条对称轴对称;
2.不能是连续的一段。
分析:
这里写图片描述
对于每一条对称轴只要求在对称轴两边的对应位置上有相同字符的位置有多少个。
答案就是2len1len(减去空串和连续的串)
但这东东它可以是不连续的…..
我们可以将
a b a a b a
1 0 1 1 0 1
发现:多项式
1 0 1 1 0 1
*1 0 1 1 0 1
假如答案某一位上是1,则xk前的系数恰好为以第k个位置(包括间隙,从0开始)为对称轴而对称的a的个数。
fft搞两波问题就解决啦~
bzoj3456
bzoj4555
bzoj3992
bzoj4503
bzoj3625
bzoj4451
bzoj3771
bzoj2179模板
bzoj3527
bzoj2194
bzoj3557
bzoj4259
xsy2182
xsy1903
xsy2106
xsy2166
xsy2179
题意:
这里写图片描述

分析:
考虑由大往小枚举最大值,对于某一最大值为 M 的区间 [l,r] ,满足 a[pi]=M 的元素将区间切割为若干子区间,那么这些子区间对长度的积对答案的某一项有等值的贡献,暴力枚举需要 O(n2) 的时间,整体考虑那些对答案某一项有贡献的子区间对的积,它们满足卷积的性质。因此只需将长度序列与其反序列作类似多项式乘法的fft,即可将时间优化为 O(nlogn) 。子区间递归处理即可。

//核心代码void gao(int x){    h[top=0]=x-l[x]+1;v[x]=1;    while (1){        h[++top]=r[x]-x+1;        if (d[r[x]+1]!=d[x]) break;        x=r[x]+1;v[x]=1;    }    for (L=-1,len=1;len<=top*2;len*=2) L++;    for (int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<L);    for (int i=0;i<=top;i++) a[i]=b[top-i]=point(h[i],0);    for (int i=top+1;i<len;i++) a[i]=b[i]=point(0,0);    fft(a,len,1);fft(b,len,1);    for (int i=0;i<len;i++) a[i]=a[i]*b[i];    fft(a,len,-1);    for (int i=1;i<=top;i++) s[i]+=(ll)a[top-i].x;}int main(){    scanf("%d",&n);    for (int i=1;i<=n;i++)        scanf("%d",d+i);    top=0;q[top].id=0;    for (int i=1;i<=n;i++){        while (top && q[top].x<d[i]) top--;        l[i]=q[top].id+1;q[++top]=node(d[i],i);    }    top=0;q[top].id=n+1;    for (int i=n;i;i--){        while (top && q[top].x<d[i]) top--;        r[i]=q[top].id-1;q[++top]=node(d[i],i);    }    for (int i=1;i<=n;i++)    if (!v[i]) gao(i);    for (int i=1;i<=n;i++)        ans+=s[i]^i;    printf("%lld\n",ans);}

12.fft

struct cp{    double x,y;    inline cp(double _x=0.0,double _y=0.0)    {        x=_x;        y=_y;    }    friend inline cp operator + (cp a,cp b)    {        return cp(a.x+b.x,a.y+b.y);    }    friend inline cp operator - (cp a,cp b)    {        return cp(a.x-b.x,a.y-b.y);    }    friend inline cp operator * (cp a,cp b)    {        return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);    }}a[N],b[N],c[N],t[N];void fft(cp *a,int len,int kd){    //kd=1时将系数表达式转换为点值表达式(就是n个点描述一个多项式)    //kd=-1时将点值表达式转换成系数表达式    for (int i=0;i<len;i++) t[i]=a[rev[i]];    for (int i=0;i<len;i++) a[i]=t[i];    //低级写法,ntt的写法更优高级    for (int i=2;i<=len;i*=2)    {        cp wn(cos(2*pi/i),kd*sin(2*pi/i));//公比        for (int k=0;k<len;k+=i)        {            cp w(1,0);//螺旋因子            for (int j=0;j<i/2;j++)            {                cp x=a[k+j];//蝶形操作                cp y=a[k+j+i/2]*w;                a[k+j]=x+y;//前半部分                a[k+j+i/2]=x-y;//后半部分                w=w*wn;            }        }    }    if(kd==-1)///IDFT      for(int i=0;i<len;i++)          a[i].x=round(a[i].x/len);//4舍5入  }//rev[]的预处理    for(m=n,n=1;n<=m<<1;n<<=1) l++;    for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);

13.ntt

void ntt(ll *a,int len,int f) {    for (int i=0;i<len;i++)        if (rev[i]>i) swap(a[i],a[rev[i]]);    for(int i=2;i<=len;i<<=1) {        ll wn=power(3,((mod-1)/i*f+mod-1)%(mod-1)),m=i>>1;        //3为mod的原根        for(int j=0;j<len;j+=i) {            ll w=1;            for(int k=0;k<m;k++,w=w*wn%mod) {                ll x=a[j+k],y=a[j+k+m]*w%mod;                a[j+k]=(x+y)%mod,a[j+k+m]=(x-y+mod)%mod;            }        }    }    if(f==-1) {        ll ni=power(len,mod-2);        for(int i=0;i<len;i++) a[i]=a[i]*ni%mod;    }}

题型:

1.对应为相乘—->将其中一个反转

0 0
原创粉丝点击