Calculation 2 HDU - 3501

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}{\rfloor}}(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\n",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\n",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*(n-1)%md*500000004%md-ans+md)%md);
75         //printf("%lld\n",ans);
76     }
77     return 0;
78 }

猜你喜欢

转载自www.cnblogs.com/hehe54321/p/9320485.html