分析(官方题解):
一点感想:
首先上面那个等式成立,然后就是求枚举gcd算贡献就好了,枚举gcd当时赛场上写了一发O(nlogn)的反演,写完过了样例,想交发现结束了
吐槽自己手速慢,但是发了题解后发现,这题连O(n)欧拉函数前缀和的都卡了,幸亏没交,还是太年轻
对于官方题解说sqrt(n)优化(其实就是n/(小于n一段数)结果是一样的,也不算什么分块),还是很简单的,做反演题的时候看到过很多,只是忘记了
如果不会请看这篇解题报告http://wenku.baidu.com/view/fbe263d384254b35eefd34eb.html
细节处理:注意特判x=1的情况,然后处理(x-1)的逆元,等比数列求和需要用,感觉这题还是能做出来的
#include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int N = 1e6+5; const LL mod = 1e9+7; int phi[N],T; LL sum[N],x,n; LL qpow(LL a,LL b){ LL ret=1; while(b){ if(b&1)ret=(ret*a)%mod; b>>=1; a=(a*a)%mod; } return ret; } inline void up(LL &x,LL y){ x+=y;if(x>=mod)x-=mod; } int main(){ phi[1]=1; for(int i=2;i<=N-5;++i)if(!phi[i]){ for(int j=i;j<=N-5;j+=i){ if(!phi[j])phi[j]=j; phi[j]=phi[j]/i*(i-1); } } for(int i=1;i<=N-5;++i)sum[i]=sum[i-1]+1ll*phi[i]; scanf("%d",&T); while(T--){ scanf("%I64d%I64d",&x,&n); if(x==1){ printf("0\n");continue; } LL inv=qpow(x-1,mod-2),ret=0; for(int i=1,j;i<=n;i=j+1){ j=n/(n/i); LL a0=qpow(x,i),qn=qpow(x,j-i+1); up(qn,mod-1); a0=a0*qn%mod*inv%mod; up(a0,mod-(j-i+1)); a0=(2ll*sum[n/i]-1)%mod*a0%mod; up(ret,a0); } printf("%I64d\n",ret); } return 0; }