ACM-ICPC 2018 沈阳赛区网络预赛 G.Spare Tire (容斥)
ai
题意:给出a的递推式,1到n中与m互质的数为i,求a[i]的和
思路:得到a的通项公式为,Sn的通项为,与m不互质的数,是取m的素因子的乘积,那么将m分解质因数,通过容斥原理,就可以得到与m不互质的数,总和减去这些数对应的a的和就是答案了。在求这些不互质数对应a的总和的时候,如果一个一个求会超时,需要直接求和。比如存在一个素因子是k,那么需要求下标为k,2k,3k,4k……的a的和,即求通项的求和,为,项数为n/k。
#include <bits/stdc++.h> using namespace std; #define ll long long #define mod 1000000007 ll prime[10100]; int pl=0; bool vis[10100]; ll n,m; void getprime() { for(ll i=2;i<10010;i++) { if(vis[i]==false) { prime[++pl]=i; } for(int j=1;j<=pl&&i*prime[j]<10010;j++) { vis[i*prime[j]]=true; if(i%prime[j]==0) break; } } } ll num[15]; int tot; void bre(ll n)//对n分解质因数 { tot=0; for(int i=1;i<=pl&&prime[i]*prime[i]<=n;i++) { if(n%prime[i]==0) { num[tot++]=prime[i]; while(n%prime[i]==0) { n/=prime[i]; } } if(n==1) break; } if(n!=1) { num[tot++]=n; } } ll inv2,inv3,inv6; ll fpow(ll a,ll b)//快速幂 { ll ans=1; ll tmp=a%mod; while(b) { if(b&1) ans=ans*tmp%mod; tmp=tmp*tmp%mod; b>>=1; } return ans; } void solve()//用二进制实现容斥原理 { ll ans=0; for(int i=0;i<(1<<tot);i++)//容斥定理所有的关系最多为2^tot { int cnt=0; ll sum=1; for(int j=0;j<tot;j++)//循环prime中的每一个运算 { if(i&(1<<j))//要掌握&运算,与i的二进制的第j位比较,看是否为1,是则选中 { cnt++;//记录prime中的每个元素 sum*=num[j]; } } ll k=n/sum; sum%=mod; ll p=(1+k)*k%mod*inv2%mod*sum%mod; ll q=k*(k+1)%mod*(2*k+1)%mod*inv6%mod*sum%mod*sum%mod; if(cnt&1) { ans-=p; if(ans<0) ans+=mod; ans-=q; if(ans<0) ans+=mod; } else { ans=(ans+p); if(ans>mod) ans-=mod; ans+=q; if(ans>mod) ans-=mod; } } printf("%lld\n",ans); } int main() { getprime(); inv2=fpow(2,mod-2); inv6=fpow(6,mod-2); while(scanf("%lld%lld",&n,&m)!=EOF) { bre(m); solve(); } }