要我们求小于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 }
时间: 2024-10-05 05:07:27