https://vjudge.net/problem/HDU-3501
不会做啊。。。记一下做法
做法是计算小于n且与n互质的数的和;根据如果gcd(i,n)==1,那么gcd(n-i,n)==1,对这些数两两一组分组,使得每组的和为n
后面自己去想了一下,想出了一个奇怪的做法。。
化简出来小于n且与n互质的数的和是$sum_{d|n}mu(d)sum_{j=1}^{{lfloor}frac{n-1}{d}{ floor}}(dj)$
于是暴力枚举因子,暴力根号n求莫比乌斯函数,得到一个O(n)做法。。。
过了。。。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 #define md 1000000007 14 #define N 100000 15 ll n,ans; 16 ll F(ll k) 17 { 18 //if(n%k!=0) return 0; 19 ll ed=(n-1)/k; 20 return (k+ed*k)%md*ed%md*500000004%md; 21 } 22 ll prime[30010],len; 23 bool nprime[100100]; 24 ll gmu(ll x) 25 { 26 //if(x==1) return 1; 27 int i,ans=1,ed=floor(sqrt(x+0.5)); 28 bool fl; 29 for(i=1;prime[i]<=ed;i++) 30 { 31 fl=0; 32 //printf("a%lld %lld ",i,x); 33 while(x%prime[i]==0) 34 { 35 if(fl) return 0; 36 fl=1; 37 x/=prime[i]; 38 ans*=(-1); 39 } 40 } 41 if(x!=1) ans*=(-1); 42 return ans; 43 } 44 int main() 45 { 46 ll i,j; 47 for(i=2;i<=N;i++) 48 { 49 if(!nprime[i]) prime[++len]=i; 50 for(j=1;j<=len&&i*prime[j]<=N;j++) 51 { 52 nprime[i*prime[j]]=1; 53 if(i%prime[j]==0) break; 54 } 55 } 56 //n=4; 57 //while(1) 58 //{scanf("%lld",&i);printf("%lld ",gmu(i));} 59 while(1) 60 { 61 scanf("%lld",&n); 62 if(n==0) break; 63 ll sq=sqrt(n+0.5); 64 if(sq*sq==n) sq--; 65 ans=0; 66 for(i=1;i<=sq;i++) 67 { 68 if(n%i!=0) continue; 69 ans=(ans+gmu(i)*F(i)+md)%md; 70 ans=(ans+gmu(n/i)*F(n/i)+md)%md; 71 } 72 sq++; 73 if(sq*sq==n) ans=(ans+gmu(sq)*F(sq)+md)%md; 74 printf("%lld ",(n*(n-1)%md*500000004%md-ans+md)%md); 75 //printf("%lld ",ans); 76 } 77 return 0; 78 }