hdu3501

要我们求小于n并且不与n互素的数字的和, 那么可以转化为1->(n-1)的和减去小于n且与n互素的数字的和

首先,有gcd(n,i)=1, 那么gcd(n,n-i)=1, 这是因为如果a%s=0, b%s=0, 那么(a-b)%s=0

所以gcd(n,i)=1, 那么gcd(n,n-i)=1, 如果gcd(n,n-i)!=1 ,那么 gcd(n,n-(n-i))!=1,所以 如果gcd(n,i)=1,那么gcd(n,n-i)=1成立

下面设小于n且与n素数的数字的和为sum

sum = a[0] + a[1] + a[2] + ... + a[phi[n]],      (a[i]表示与n互素的数字)

sum = (n-a[0]) + (n-a[1]) + (n-a[2])+...+(n-a[phi[n]])

两个式子相加, 2*sum = phi[n]*n->sum = phi[n]*n/2

1->(n-1)的和为n*(n-1)/2

所以最终答案为n*(n-1)/2 - phi[n]*n/2

数据太大,要用long long

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <algorithm>
 5 #include <iostream>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <map>
10 #include <set>
11 #include <string>
12 #include <math.h>
13 using namespace std;
14 #pragma warning(disable:4996)
15 typedef  long long  LL;                   
16 const int INF = 1<<30;
17 /*
18 
19 */
20 
21 
22 int euler(int n)
23 {
24     int m = sqrt(n) + 0.5;
25     int ans = n;
26     for (int i = 2; i <= m; ++i)
27     if (n%i == 0)
28     {
29         ans = ans / i * (i - 1);
30         while (n%i == 0) n /= i;
31     }
32     if (n > 1) ans = ans / n *(n - 1);
33     return ans;
34 }
35 int main()
36 {
37     
38     
39     LL n;
40     while (scanf("%I64d", &n), n)
41     {
42         LL t = euler(n)*n/2;
43         LL ans = n*(n - 1) / 2 - t;
44         printf("%I64d\n", ans % 1000000007);
45     }
46     return 0;
47 }
View Code

 

posted @ 2015-05-09 09:00  justPassBy  阅读(328)  评论(0编辑  收藏  举报