• 【SDOI2015】序列统计 解题报告


    2119: 【BZOJ3992】【SDOI2015】序列统计

    Description

    (C)有一个集合(S),里面的元素都是小于(M)的非负整数。

    他用程序编写了一个数列生成器,可以生成一个长度为(N)的数列,数列中的每个数都属于集合(S)

    (C)用这个生成器生成了许多这样的数列。但是小(C)有一个问题需要你的帮助:给定整数(x),求所有可以生成出的,且满足数列中所有数的乘积(mod M)的值等于(x)的不同的数列的有多少个。

    (C)认为,两个数列({A_i})({B_i})不同,当且仅当至少存在一个整数(i),满足(A_i≠B_i)。另外,小(C)认为这个问题的答案可能很大,因此他只需要你帮助他求出答案(mod 1004535809)的值就可以了。

    Input

    一行,四个整数,(N)(M)(x)(|S|),其中(|S|)为集合(S)中元素个数。

    第二行,(|S|)个整数,表示集合(S)中的所有元素。

    Output

    一行,一个整数,表示你求出的种类数(mod 1004535809)的值。

    HINT

    对于(10\%)的数据,(1≤N≤1000)

    对于(30\%)的数据,(3≤M≤100)

    对于(60\%)的数据,(3≤M≤800)

    对于全部的数据,(1≤N≤10^9)(3≤M≤8000)(M)为质数,(1≤x≤M−1),输入数据保证集合(S)中元素不重复


    先吐槽一波部分分吧...

    明显有一个矩阵快速幂的做法,然后通过不了60pts,请问这个点的分怎么拿呢?

    (dp_{i,j})(i)个数乘积为(j)的方案

    [dp_{i,j}=sum dp_{i-1,ab\% m=j} ]


    思路:利用原根转换问题,然后生成函数用多项式快速幂求一下就行了。

    对原根,若(g)(m)的原根,则(g^0,g^1,dots,g^{varphi(m)-1})遍历(mod m)的最小剩余系,就是它们有个一一对应关系

    关于求原根,把(varphi(m)-1)分解质因数得到每个质因子(p_i),然后从小到大枚举原根(g),检验每个质因子是否有(g^{frac{varphi(m)-1}{p_i}}equiv 1 pmod m),如果所有质因子都没有,(g)就是原根,因为原根非常的小,所以这个复杂度是正确的。

    然后把前面(ab\%m=j)换掉,就成了((a’+b')\%(m-1)=j')

    然后你构造生成函数(f_i=sum is_ix^{i-1})(is_i)代表最开始转换后这个值存不存在。

    然后发现结果就是这个( t f^n),写一个(NTT)快速幂就成了,复杂度(O(mlog mlog n))


    Code:

    #include <cstdio>
    #include <algorithm>
    const int N=(1<<14)+10;
    const int mod=1004535809,Gi=334845270;
    #define add(x,y,p) ((x+y)%p)
    #define mul(x,y,p) (1ll*(x)*(y)%p)
    int qp(int d,int k,int p){int f=1;while(k){if(k&1) f=mul(f,d,p);d=mul(d,d,p),k>>=1;}return f;}
    int A[N],B[N],F[N],D[N],n,m,turn[N],to[N],len=1;
    int GetG(int x)
    {
        int s[1010]={0},phi=x-1,t=x-1;
        for(int i=2;i*i<=t;i++)
        {
            if(t%i==0)
            {
                s[++s[0]]=i;
                while(t%i==0) t/=i;
            }
        }
        if(t!=1) s[++s[0]]=t;
        for(int i=2;i<x;i++)
        {
            int flag=1;
            for(int j=1;j<=s[0];j++)
                if(qp(i,phi/s[j],x)==1)
                {
                    flag=0;
                    break;
                }
            if(flag) return i;
        }
        return -1;
    }
    void NTT(int *a,int typ)
    {
        for(int i=0;i<len;i++) if(i<turn[i]) std::swap(a[i],a[turn[i]]);
        for(int le=1;le<len;le<<=1)
        {
            int wn=qp(typ?3:Gi,(mod-1)/(le<<1),mod);
            for(int p=0;p<len;p+=le<<1)
            {
                int w=1;
                for(int i=p;i<p+le;i++,w=mul(w,wn,mod))
                {
                    int tx=a[i],ty=mul(w,a[i+le],mod);
                    a[i]=add(tx,ty,mod);
                    a[i+le]=add(tx,mod-ty,mod);
                }
            }
        }
        if(!typ)
        {
            int inv=qp(len,mod-2,mod);
            for(int i=0;i<len;i++) a[i]=mul(a[i],inv,mod);
        }
    }
    void Rev()
    {
        int L=-1;for(int i=1;i<len;i<<=1) ++L;
        for(int i=1;i<len;i++) turn[i]=turn[i>>1]>>1|(i&1)<<L;
    }
    void polymul(int *a,int *b)
    {
        for(int i=0;i<len;i++) A[i]=a[i],B[i]=b[i],a[i]=0;
        NTT(A,1),NTT(B,1);
        for(int i=0;i<len;i++) A[i]=mul(A[i],B[i],mod);
        NTT(A,0);
        for(int i=0;i<len;i++) a[i%(m-1)]=add(a[i%(m-1)],A[i],mod);
    }
    int main()
    {
        int s,x;
        scanf("%d%d%d%d",&n,&m,&x,&s);
        int g=GetG(m);
        while(len<=(m<<1))len<<=1;Rev();
        for(int f=1,i=0;i<m-1;i++,f=mul(f,g,m))
            to[f]=i;
        for(int x,i=1;i<=s;i++)
        {
            scanf("%d",&x);
            if(x) F[to[x]]=1,D[to[x]]=1;
        }
        --n;
        while(n)
        {
            if(n&1) polymul(F,D);
            polymul(D,D);
            n>>=1;
        }
        printf("%d
    ",F[to[x]]);
        return 0;
    }
    

    2018.12.17

  • 相关阅读:
    linux下的开源移动图像监测程序--motion编译与配置【转】
    motion程序的移植和安装【转】
    Android5.1 在init.rc 中添加自己的服务【转】
    Android进程回收机制LMK(Low Memory Killer)【转】
    Linux内核OOM机制的详细分析【转】
    Android——build.prop 解析【转】
    Android——build.prop 解析【转】
    【转】ios的控件UIScrollView的位置定位---------逐渐积累
    【转】IOS图像拉伸解决方案
    【转】NSString属性什么时候用copy,什么时候用strong?
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10133434.html
Copyright © 2020-2023  润新知