省选前不得不复(学)习一下数学了。
从xjoi上的一道题谈起:
你需要解决5个子问题:([tex]T[/tex]为数据组数)
(1)求[tex]ax \equiv 1 (\text{mod } p)[/tex]的最小正整数解[tex]x[/tex]
数据范围:[tex] 1 \leq a,p \leq 10^9 , 1 \leq T \leq 100000[/tex]
(2)求[tex]a^x \equiv 1 (\text{mod } p)[/tex]的最小正整数解[tex]x[/tex]
数据范围:[tex]1 \leq a,p \leq 10^9 , 1 \leq T \leq 2000[/tex] ,[tex]p[/tex]为素数且[tex]a[/tex]与[tex]p[/tex]互质。
(3)求[tex]\sum_{i=1}^n\sum_{j=1}^m\text{gcd}(i,j)[/tex]
数据范围:[tex]1 \leq n,m \leq 10^7, 1 \leq T \leq 1000[/tex]
(4)求[tex]\sum_{i=1}^n \left \lfloor \frac{n}{i} \right \rfloor[/tex]
数据范围:[tex]1 \leq n \leq 10^7, 1 \leq T \leq 100000[/tex]
(5)求[tex]c_{i}=\sum_{j=1}^{n-i}a_j b_{j+i}, 1 \leq i < n[/tex]
数据范围:[tex] n \leq 100000, 1 \leq a_i, b_i \leq 100[/tex]
(1)扩展欧几里得
非常显然,这就是个扩展欧几里得,记忆力不好就只好现推了。
当[tex]ab \neq 0[/tex]时,一定存在整数对[tex]x,y[/tex]使得[tex]ax+by \equiv \text{gcd}(a,b)[/tex]
设[tex] a>b[/tex]
[tex]b=0[/tex]时,[tex]\text{gcd}(a,b)=a[/tex],此时[tex]x=1,y=0[/tex]
[tex]b \neq 0[/tex]时,设
[tex]ax_{1}+by_{1}=\text{gcd}(a,b)
[tex]bx_{2}+(a \text{ mod } b) y_{2} = \text{gcd}(b,a \text{ mod } b)
显然有[tex]\text{gcd}(a,b)=\text{gcd}(b,a \text{ mod } b)[/tex]
那么就有[tex]ax_{1}+by_{1}=bx_{2}+(a \text{ mod } b) y_{2}[/tex]
接着把[tex] (a \text{ mod } b)[/tex]用[tex](a- \left \lfloor \frac{a}{b} \right \rfloor b)[/tex]替换掉。
可以得到[tex]ax_1+by_1=ay_2+b(x_2- \left \lfloor \frac{a}{b} \right \rfloor y_2)[/tex]
解为[tex]x_1=y_2,y_1=x_2- \left \lfloor \frac{a}{b} \right \rfloor y_2[/tex]
整个过程递归进行,时间复杂度[tex]\text{O} (T\text{log}a)[/tex]
(2)离散对数(小步大步算法)
(为了完整性我粘过来=。=)
(3)(4)线性筛
继续orz jcvb
(3)相同一段一起算。
(4)可以转化成约数和的前缀和,才可以满分。
(5)FFT
反转第二个数组,发现求的就是两个数组的卷积。上FFT即可。
无聊不如贴份代码好了233
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const double pi=3.1415926535897932384626; struct problem_1{ ll exgcd(ll &x,ll &y,ll a,ll b){ if(!b){ x=1; y=0; return a; } ll xx,yy,d=exgcd(xx,yy,b,a%b); x=yy; y=xx-(a/b)*yy; return d; } ll equ(ll a,ll b,ll c){ ll x,y,d=exgcd(x,y,a,c); if(b%d) return -1; ll e=x*(b/d)%c; while(e<0) e+=c/d; return e; } void solve(){ int tc; scanf("%d",&tc); ll a,p,x,y,d; while(tc--){ scanf("%lld%lld",&a,&p); printf("%lld\n",equ(a,1,p)); } } }p_1; struct problem_2{ int pow(int a,int b,int c){ int an=1; while(b){ if(b&1) an=1ll*an*a%c; b>>=1; a=1ll*a*a%c; } return an; } int getans(int a,int p){ int t=p-1,ans=p; for(int i=1;i*i<=t;i++){ if(t%i==0){ if(pow(a,i,p)==1) ans=min(ans,i); if(pow(a,t/i,p)==1) ans=min(ans,t/i); } } return ans; } void solve(){ int tc,a,p; scanf("%d",&tc); while(tc--){ scanf("%d%d",&a,&p); printf("%d\n",getans(a,p)); } } }p_2; int flag[10000010],g[10000010],prime[2000000],pcnt; long long phi[10000010],f[10000010]; struct problem_3{ void sieve(int n){ memset(flag,0,sizeof(flag));pcnt=0; for(int i=2;i<=n;i++){ if(!flag[i]) prime[++pcnt]=i,phi[i]=i-1; for(int j=1;j<=pcnt && i*prime[j]<=n;j++){ flag[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; }else{ phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } phi[1]=1; for(int i=2;i<=n;i++) phi[i]+=phi[i-1]; } void solve(){ sieve(10000000); int tc,n,m,n1; ll ans; scanf("%d",&tc); while(tc--){ scanf("%d%d",&n,&m); if(n>m) swap(n,m); ans=0; for(int i=1;i<=n;i=n1+1){ n1=min(n/(n/i),m/(m/i)); ans+=1ll*(n/i)*(m/i)*(phi[n1]-phi[i-1]); } printf("%lld\n",ans); } } }p_3; struct problem_4{ void sieve(int n){ for(int i=2;i<=n;i++){ if(!flag[i]) prime[++pcnt]=i,g[i]=1,f[i]=2; for(int j=1;j<=pcnt && prime[j]*i<=n;j++){ flag[i*prime[j]]=1; if(i%prime[j]==0){ g[i*prime[j]]=g[i]+1; f[i*prime[j]]=f[i]/(g[i]+1)*(g[i]+2); break; }else{ f[i*prime[j]]=f[i]*2; g[i*prime[j]]=1; } } } f[1]=1; for(int i=2;i<=n;i++) f[i]+=f[i-1]; } void solve(){ sieve(10000000); int tc,n; scanf("%d",&tc); ll ans; while(tc--){ scanf("%d",&n); printf("%lld\n",f[n]); } } }p_4; struct problem_5{ struct cpx{ double a,b; cpx operator + (const cpx&o)const{ return (cpx){a+o.a,b+o.b};} cpx operator - (const cpx&o)const{ return (cpx){a-o.a,b-o.b};} cpx operator * (const cpx&o)const{ return (cpx){a*o.a-b*o.b,b*o.a+a*o.b};} }a[400010],b[400010]; int an[400010],len,tmp[100]; int rev(int x){ tmp[0]=0; for(;x;x>>=1) tmp[++tmp[0]]=x&1; int t=0; for(int i=1;i<=tmp[0];i++) if(tmp[i]) t+=1<<(len-i); return t; } void fft(cpx *A,int n,int fl=1){ for(int i=0;i<n;i++){ int t=rev(i); if(i<t) swap(A[i],A[t]); } for(int m=2;m<=n;m<<=1){ cpx w=(cpx){cos(fl*2*pi/(double)m),sin(fl*2*pi/(double)m)}; for(int k=0;k<n;k+=m){ cpx cur=(cpx){1,0}; for(int j=k;j<k+(m>>1);j++,cur=cur*w){ cpx t=cur*A[j+(m>>1)],u=A[j]; A[j]=u+t; A[j+(m>>1)]=u-t; } } } } void solve(){ int n; scanf("%d",&n); memset(a,0,sizeof(a));memset(b,0,sizeof(b)); for(int i=0;i<n;i++) scanf("%lf",&a[i].a); for(int i=0;i<n;i++) scanf("%lf",&b[n-i-1].a); len=0; while((1<<len)<2*n) len++; fft(a,(1<<len)); fft(b,(1<<len)); for(int i=0;i<(1<<len);i++) a[i]=a[i]*b[i]; fft(a,(1<<len),-1); for(int i=0;i<(1<<len);i++) an[i]=(int)(a[i].a/(double)(1<<len)+0.5); for(int i=n-2;~i;i--) printf("%d\n",an[i]); } }p_5; int main(){ int testid; scanf("%d",&testid); if(testid>=1 && testid<=2) p_1.solve(); else if(testid>=3 && testid<=6) p_2.solve(); else if(testid>=7 && testid<=10) p_3.solve(); else if(testid>=11 && testid<=14) p_4.solve(); else p_5.solve(); return 0; }