[数论记录]P4464 [国家集训队]JZPKIL

command_block

2019-10-18 13:30:58

Personal

神仙题目,做一题学一堆系列…… 题意:求$\sum_{i=1}^{n}gcd(i,n)^x lcm(i,n)^y \bmod (10^9+7)$ $n<=10^{18};\ x,y<3000$ $ANS=\sum_{i=1}^{n}gcd(i,n)^x lcm(i,n)^y$ $=n^y\sum_{i=1}^{n}gcd(i,n)^{x-y}i^y$ 先忽略掉$n^y$。 $=\sum_{d|n}\sum_{i=1}^{n}[(i,n)==d]d^{x-y}i^y$ $=\sum_{d|n}\sum_{i=1}^{n/d}[(i,\frac{n}{d})==1]d^{x-y}(id)^y$ $=\sum_{d|n}d^x\sum_{i=1}^{n/d}[(i,\frac{n}{d})==1]i^y$ $=\sum_{d|n}d^x\sum_{i=1}^{n/d}i^y\sum\limits_{j|i,j|\frac{n}{d}}\mu(j)$ $=\sum_{d|n}d^x\sum\limits_{j|\frac{n}{d}}\mu(j)\sum_{j|i}^{n/d}i^y$ $=\sum_{d|n}d^x\sum\limits_{j|\frac{n}{d}}\mu(j)\sum_{i=1}^{n/dj}(ij)^y$ $=\sum_{d|n}d^x\sum\limits_{j|\frac{n}{d}}\mu(j)j^y\sum_{i=1}^{n/dj}i^y$ 推导到这里,先冷静观察一下式子: 后面$\sum_{i=1}^{n/dj}i^y$是自然数幂和,这个好办。 伯努利数$O(y)$搞出多项式系数就好,需要$O(y^2)$的预处理 。 不会的话请见 [多项式计数杂谈](https://www.luogu.com.cn/blog/command-block/sheng-cheng-han-shuo-za-tan) 得到$\sum_{i=1}^{n}i^y=\sum_{i=0}^{y+1}c_in^i$($c$是多项式系数) $ANS=\sum_{d|n}d^x\sum\limits_{j|\frac{n}{d}}\mu(j)j^y\sum_{i=0}^{y+1}c_i(n/dj)^i$ $=\sum_{i=0}^{y+1}c_i\sum_{d|n}d^x\sum\limits_{j|\frac{n}{d}}\mu(j)j^y(n/dj)^i$ 仔细看看就会发现后面的$\sum_{d|n}d^x\sum\limits_{j|\frac{n}{d}}\mu(j)j^y(n/dj)^i$是三个函数卷积的形式: $F1(n)=n^x;\ \ F2(n)=\mu(n)n^y;\ \ F3(n)=n^i$ 那么这个卷积后的东西$R(n)=F1*F2*F3$也应该是个积性函数。 我们只要设法求出任意的$R(p^k)$($p$指质数),就可以利用积性了。 $R(p^k)=\sum\limits_{j|p^k}\mu(j)j^y\sum_{d|\frac{p^k}{j}}d^x(p^k/dj)^i$ 根据$\mu$很有可能为0,这里的$j=p$或$1$。 - $j=1$ 贡献$=\sum_{d|p^k}d^x(p^k/d)^i$ $=p^{ik}\sum_{d|p^k}d^{x-i}$ $=p^{ik}\sum_{t=0}^{k}p^{t(x-i)}$ 为了躲掉逆元,我们把负指数变一下: $=\sum_{t=0}^{k}p^{tx+(k-t)i}$ 这里$k$很小,暴力求就好,下面同理。 - $j=p$ $-p^y\sum_{d|p^{k-1}}d^x(p^{k-1}/d)^i$ $=-p^{y}($上面$k-1$的情况$)$ 懒得汇总了…… 我们算$y$次这个$R$就能解决问题了。 上面的全部暴力快速幂实现,求一次也就$log^2$。 那么现在还剩下一个问题就是分解,Prho硬上即可,分解的结果要保存下来。 总复杂度$O(T(\sqrt[4]{n}+ylog^2n)+y^2)$ ```cpp #include<algorithm> #include<cstdio> #define mod 1000000007 #define ll long long using namespace std; ll powM(ll a,ll t=mod-2) { ll ans=1;a%=mod; while(t){ if(t&1)ans=ans*a%mod; a=a*a%mod; t>>=1; }return ans; } namespace BNL { #define Maxn 3050 ll B[Maxn],ifac[Maxn],fac[Maxn]; void Init() { fac[0]=ifac[0]=1; for (int i=1;i<=3005;i++){ ifac[i]=ifac[i-1]*powM(i)%mod; fac[i]=fac[i-1]*i%mod; }B[0]=1; for (int j=1;j<=3005;j++){ for (int i=0;i<j;i++) B[j]=(B[j]+B[i]*ifac[j-i+1])%mod; B[j]=mod-B[j]; } } void getf(ll *f,int k) { for (int i=1;i<=k+1;i++) f[i]=B[k-i+1]*ifac[i]%mod*fac[k]%mod; f[0]=0;if (k)f[k]++; } } inline ll mul(ll a,ll b,ll m){ ll d=((long double)a/m*b+0.5); ll r=a*b-d*m; return r<0?r+m:r; } ll powM(ll a,ll t,ll m) { ll ans=1; while(t){ if (t&1)ans=mul(ans,a,m); a=mul(a,a,m); t>>=1; }return ans; } bool mr(ll n,ll a) { ll t=n-1; while(!(t&1))t>>=1; ll buf=powM(a,t,n); if (buf==1||buf==n-1)return 0; while((t<<=1)<n-1){ buf=mul(buf,buf,n); if (buf==n-1)return 0; }return 1; } const int testp[8]={2,3,5,7,13,19,61,233}; bool ptest(ll n) { if (n<2)return 0; for (int i=2;i*i<=min(n,10000ll);i++) if (n%i==0)return 0; if (n<=10000)return 1; for (int i=0;i<8;i++) if (mr(n,testp[i]))return 0; return 1; } inline ll gcd(ll a,ll b){ if(a==0)return b; if(a<0)a=-a; ll t; while(b){t=a%b;a=b;b=t;} return a; } ll sav[150]; const int lim=128; ll prho(ll n,ll c) { ll x1=(c+1)%n,x2=(mul(x1,x1,n)+c)%n,buf; int tot=0; while(1){ buf=mul(x1-x2,buf,n); sav[++tot]=x1-x2; if (tot==lim){ if (gcd(buf,n)>1)break; tot=0; } x1=(mul(x1,x1,n)+c)%n; x2=(mul(x2,x2,n)+c)%n; x2=(mul(x2,x2,n)+c)%n; } for (int i=1;i<=tot;i++){ buf=gcd(sav[i],n); if (buf>1)return buf; }return n; } int tot,savc[127]; ll savf[127]; void factor(ll n) { if (ptest(n)){ for (int i=1;i<=tot;i++) if (savf[i]==n) {savc[i]++;return ;} savf[++tot]=n;savc[tot]=1; return ; } ll sav=prho(n,rand()%(n-1)+1); while(sav==n)sav=prho(n,rand()%(n-1)+1); factor(sav);factor(n/sav); } ll c[3050],n;int x,y; ll calc(ll p,int k,int i) { ll ans=0; for (int t=0;t<=k;t++) ans=(ans+powM(p,t*x+(k-t)*i))%mod; return ans; } void solve() { scanf("%lld%d%d",&n,&x,&y); ll savn=n%mod; BNL::getf(c,y); for (int i=2;i<=10000&&i*i<=n;i++) if (n%i==0){ savf[++tot]=i; while (n%i==0){ n/=i;savc[tot]++; } } if (n>1)factor(n); ll ans=0; for (int i=0;i<=y+1;i++){ ll buf=1; for (int j=1;j<=tot;j++){ ll sav=calc(savf[j],savc[j],i); sav=(sav-powM(savf[j],y) *calc(savf[j],savc[j]-1,i))%mod; buf=buf*sav%mod; } ans=(ans+c[i]*buf)%mod; }printf("%lld\n",(ans*powM(savn,y)%mod+mod)%mod); for (int i=1;i<=tot;i++)savc[i]=0; tot=0; } int main() { BNL::Init(); int T;scanf("%d",&T); while(T--)solve(); return 0; } ```