BZOJ 4407 于神之怒加强版
题面:
4407: 于神之怒加强版
Time Limit: 80 Sec Memory Limit: 512 MBSubmit: 702 Solved: 329
[Submit][Status][Discuss]
Description
给下N,M,K.求
Input
输入有多组数据,输入数据的第一行两个正整数T,K,代表有T组数据,K的意义如上所示,下面第二行到第T+1行,每行为两个正整数N,M,其意义如上式所示。
Output
如题
Sample Input
1 2
3 3
3 3
Sample Output
20
HINT
1<=N,M,K<=5000000,1<=T<=2000
$\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)^{k}$
$=\sum_{d=1}^{min(n,m)}d^{k}\sum_{T=1}^{min(n,m)}\mu(\frac{T}{d})\lfloor\frac{n}{T}\rfloor\lfloor\frac{n}{T}\rfloor$
$=\sum_{T=1}^{min(n,m)}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}{\mu(\frac{T}{d})d^{k}}$
令$f[T]=\sum_{d|T}{\mu(\frac{T}{d})d^k}$,之后线性筛求出$f[T]$前缀和,每个询问分块处理。
时间复杂度$O(N+T\sqrt{n})$。
1 #pragma GCC optimize("O3") 2 #include<iostream> 3 #include<cstdio> 4 using namespace std; 5 const int mod=1e9+7; 6 const int maxn=5000000; 7 int prime[670000],g[maxn+1],f[maxn+1]; 8 bool book[maxn+1]; 9 int n,m,k,T,cnt; 10 int qpow(int x,int y) 11 { 12 int ans=1; 13 while(y) 14 { 15 if(y&1) 16 ans=1LL*ans*x%mod; 17 x=1LL*x*x%mod; 18 y>>=1; 19 } 20 return ans; 21 } 22 void init() 23 { 24 g[1]=1; 25 for(int i=2;i<=maxn;i++) 26 { 27 if(!book[i]) 28 { 29 prime[++cnt]=i; 30 f[i]=qpow(i,k); 31 g[i]=f[i]-1; 32 } 33 for(int j=1;j<=cnt&&1LL*i*prime[j]<=maxn;j++) 34 { 35 book[i*prime[j]]=true; 36 if(i%prime[j]!=0) 37 g[i*prime[j]]=1LL*g[i]*g[prime[j]]%mod; 38 else 39 g[i*prime[j]]=1LL*g[i]*f[prime[j]]%mod; 40 } 41 } 42 for(int i=2;i<=maxn;i++) 43 g[i]=(g[i-1]+g[i])%mod; 44 45 } 46 int query(int x,int y) 47 { 48 int i,last; 49 int ans=0; 50 if(n>m) 51 n^=m^=n^=m; 52 for(i=1;i<=n;i=last+1) 53 { 54 last=min(n/(n/i),m/(m/i)); 55 ans=(ans+1LL*(n/i)*(m/i)%mod*(g[last]-g[i-1]+mod)%mod)%mod; 56 } 57 return ans; 58 } 59 int main() 60 { 61 scanf("%d%d",&T,&k); 62 init(); 63 while(T--) 64 { 65 scanf("%d%d",&n,&m); 66 printf("%d\n",query(n,m)); 67 } 68 }
(PS:可以手动开$O_{2}O_{3}$(卡常数利器),可以快上几百ms)