zoukankan      html  css  js  c++  java
  • wmq的A×B Problem

    wmq的A×B Problem

    题目链接:http://oj.xjtuacm.com/problem/13/

    题目大意:$T$组数据,每组给出$n$个数$a_i$及一个素数$m$,求这$n$个数两两相乘模$m$余$k$有多少个($0leqslant k < m$).

    数论+FFT

    原根的概念

    设$n geqslant 1$,$(a,n)=1$,使得$a^d equiv 1(mod n)$成立的最小的正整数$d$,被称为$a$对模$n$的阶,记做$delta_n(a)$.

    当$delta_n(a)=varphi(n)$时,称$a$为模$n$的一个原根.

    一些性质

    1.质数必存在原根(有缘再证);

    2.若$(a,n)=1$,$a^d equiv 1 (mod n)$,则$delta_n(a)|d$.

        证明:设$d=kdelta_n(a)+r$,其中$0 leqslant r < delta_n(a)$,则有

                $a^d equiv a^{kdelta_n(a)+r} equiv a^r equiv 1(mod n)$.

                由$delta_n(a)$的最小性得,$r=0$.

                $ herefore delta_n(a)|d$.

    2.若$(a,n)=1$,$a^k equiv a^l (mod n)$,则$k equiv l(mod delta_n(a))$.

        证明:不妨设$k geqslant l$,则有$a^{k-l} equiv 1 (mod n)$.

               $ecause delta_n(a)|k-l$.

               $ herefore k equiv l(mod delta_n(a))$.

    3.若$(a,n)=1$,则$a^0,a^1,...,a^{delta_n(a)-1}$模$n$两两不同余。特别地,当$a$为$n$的原根时,这$varphi(n)$个数是模$n$的一个缩系.

        证明:假设存在$0 leqslant k,l < delta_n(a)$,使得$a^k equiv a^l (mod n)$.

                由2.知,$k equiv l (mod delta_n(a))$.

                $ herefore a^0,a^1,...a^{delta_n(a)-1}$两两不同余。

         当$a$是模$n$的原根时,$delta_n(a) = varphi(n)$,故这$varphi(n)$个数是模$n$的一个缩系.


    因为题目中$m$为质数,故必存在原根,设其中一个原根为$r$。

    将模$m$为零的数单独处理:$ans[0]=mod[0] imes (n-mod[0])+mod[0] imes (mod[0]-1)/2$;

    将所有的模m不为零的数$a_i$写成$r^x$的形式,从而构造出一个关于$r$的多项式:$S=sum_{i=0}^{varphi(m)-1}A_ir^i$.

    考虑任意两个数的乘积$r^i imes r^j = r^{i+j}$,将多项式$S$作平方,删去多余项(直接相乘包含了$a_i imes a_i$的结果),即为答案.

    复杂度为$O(varphi(m) imes lg(varphi(m)) )$.

    代码如下:

      1 #include <cstdio>
      2 #include <cmath>
      3 #include <iostream>
      4 #include <cstring>
      5 #define N 60010
      6 using namespace std;
      7 typedef long long ll;
      8 ll T,n,m,t,r,len,phi;
      9 ll ans[N],mod[N],rt[N],temp[4*N];
     10 const double pi=acos(-1.0);
     11 struct Complex{
     12     double r,i;
     13     Complex(double r=0,double i=0):r(r),i(i){};
     14     Complex operator+(const Complex &rhs){return Complex(r+rhs.r,i+rhs.i);}
     15     Complex operator-(const Complex &rhs){return Complex(r-rhs.r,i-rhs.i);}
     16     Complex operator*(const Complex &rhs){return Complex(r*rhs.r-i*rhs.i,i*rhs.r+r*rhs.i);}
     17 }a[4*N],b[4*N],c[4*N];
     18 void sincos(double theta,double &p0,double &p1){
     19     p0=sin(theta);p1=cos(theta);
     20 }
     21 void fft_main(Complex P[], ll n, ll oper){
     22     for(ll i=1,j=0;i<n-1;i++){
     23         for(ll s=n;j^=s>>=1,~j&s;);
     24         if(i<j)swap(P[i],P[j]);
     25     }
     26     Complex unit_p0;
     27     for(ll d=0;(1<<d)<n;d++){
     28         ll m=1<<d,m2=m*2;
     29         double p0=pi/m*oper;
     30         sincos(p0,unit_p0.i,unit_p0.r);
     31         for(ll i=0;i<n;i+=m2){
     32             Complex unit=1;
     33             for(ll j=0;j<m;j++){
     34                 Complex &P1=P[i+j+m],&P2=P[i+j];
     35                 Complex t=unit*P1;
     36                 P1=P2-t; P2=P2+t;
     37                 unit=unit*unit_p0;
     38             }
     39         }
     40     }if(oper==-1)for(ll i=0;i<len;i++)P[i].r/=len;
     41 }
     42 void fft(Complex a[],Complex b[],ll len){
     43     fft_main(a,len,1);fft_main(b,len,1);
     44     for(ll i=0;i<len;++i)c[i]=a[i]*b[i];
     45     fft_main(c,len,-1);
     46 }
     47 void fft_init(){
     48     len=1;
     49     while(len<2*phi)len<<=1;
     50     ll i=0;
     51     for(ll x=1;i<phi;++i){
     52         rt[i]=mod[x];
     53         a[i].r=b[i].r=rt[i];
     54         a[i].i=b[i].i=0;
     55         x=(x*r)%m;
     56     }
     57     for(;i<len;++i){
     58         a[i].r=b[i].r=0;
     59         a[i].i=b[i].i=0;
     60     }
     61 }
     62 ll powmod(ll a,ll n,ll m){
     63     ll r=1,t=a;
     64     while(n){
     65         if(n&1)r=(r*t)%m;
     66         t=(t*t)%m;
     67         n>>=1;
     68     }
     69     return r;
     70 }
     71 ll Root(ll m){
     72     for(ll i=2,j;i<m;++i){
     73         for(j=2;j<phi;++j)
     74             if(powmod(i,j,m)==1)
     75                 break;
     76         if(j==phi)return i;
     77     }
     78     return 0;
     79 }
     80 ll in(){
     81     ll res=0,flag=0,ch;
     82     if((ch=getchar())=='-')flag=1;
     83     else if('0'<=ch&&ch<='9')res=ch-'0';
     84     while('0'<=(ch=getchar())&&ch<='9')res=res*10+ch-'0';
     85     return flag?-res:res;
     86 }
     87 void out(ll x){
     88     if(x>9)out(x/10);
     89     putchar(x%10+'0');
     90 }
     91 void solve(){
     92     for(ll i=0;i<len;++i){
     93         temp[i]=c[i].r+0.5;
     94         temp[i]/=2;
     95     }
     96     for(ll i=0;i<phi;++i){
     97         temp[2*i]-=rt[i]*rt[i]/2;
     98         temp[2*i]+=rt[i]*(rt[i]-1)/2;
     99     }
    100     for(ll i=0,x=1;i<len;++i){
    101         ans[x]+=temp[i];
    102         x=(x*r)%m;
    103     }
    104     ans[0]=mod[0]*(n-mod[0])+mod[0]*(mod[0]-1)/2;
    105 }
    106 void init(){
    107     memset(temp,0,sizeof(temp));
    108     n=in();m=in();
    109     for(ll i=0;i<m;++i)mod[i]=0;
    110     for(ll i=0;i<m;++i)ans[i]=0;
    111     for(ll i=0;i<n;++i){
    112         t=in();
    113         mod[t%m]++;
    114     }
    115 }
    116 int main(void){
    117     T=in();
    118     while(T--){
    119         init();
    120         phi=m-1;
    121         r=Root(m);
    122         fft_init();
    123         fft(a,b,len);
    124         solve();
    125         for(ll i=0;i<m;++i){
    126             out(ans[i]);
    127             puts("");
    128         }
    129     }
    130 }
  • 相关阅读:
    Java并发编程的艺术(二)——volatile、原子性
    Java并发编程的艺术(一)——并发编程的注意问题
    算法——朋友圈(并查集)
    算法——汉诺塔问题
    算法——接雨水
    算法——n皇后问题
    深入理解Java虚拟机(八)——类加载机制
    深入理解Java虚拟机(七)——类文件结构
    转-项目管理5阶段|一位高级项目经理的4年项目经验分享
    什么是信息系统项目管理师(高级项目经理)
  • 原文地址:https://www.cnblogs.com/barrier/p/6697179.html
Copyright © 2011-2022 走看看