输入一个数n,输出小于n且与n互素的整数个数
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
long long n,m,ans;
while(cin>>n&&n!=0)
{
ans=n;
if(n%2==0)//只搜n/2次,不然可能超一组 (也可能不超)
{
while(n%2==0) n/=2;
ans=ans/2;
}
for(long long i=3;i*i<=n;i+=2)
//每找到一个就更改上界,这个优化很多,所以直接copy刘汝佳的代码会超时
{
if(n%i==0)
{
while(n%i==0) n/=i;
ans=ans/i*(i-1);
}
}
if(n>1) ans=ans/n*(n-1);
cout<<ans<<endl;
}
return 0;
}
用启发式分解这题会优化很多。
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <algorithm>
typedef long long ll;
const int s = 10, MAX_F = 70;
ll cnt, f[MAX_F];
inline ll mul_mod(ll a, ll b, ll m)
{
ll c = a*b-(ll)((long double)a*b/m+0.5)*m;
return c<0 ? c+m : c;
}
ll fast_exp(ll a, ll x, ll m)
{
ll b = 1;
while (x)
{
if (x & 1)
b = mul_mod(b, a, m);
a = mul_mod(a, a, m);
x >>= 1;
}
return b;
}
bool MR(ll n)
{
if (!(n&1))
return n == 2;
ll t = 0, u;
for (u = n-1; !(u&1); u >>= 1)
++t;
for (int i = 0; i < s; ++i)
{
ll a = rand()%(n-2)+2, x = fast_exp(a, u, n);
for (ll j = 0, y; x != 1 && j < t; ++j, x = y)
{
y = mul_mod(x, x, n);
if (y == 1 && x != n-1)
return false;
}
if (x != 1)
return false;
}
return true;
}
inline ll abs(ll x)
{
return x<0 ? -x : x;
}
ll gcd(ll a, ll b)
{
return b ? gcd(b, a%b) : a;
}
ll PR(ll n, ll a)
{
ll x = rand()%n, y = x, k = 1, i = 0, d = 1;
while (d == 1)
{
if ((x = (mul_mod(x, x, n)+a)%n) == y)
return n;
d = gcd(n, abs(y-x));
if (++i == k)
{
k <<= 1;
y = x;
}
}
return d;
}
void decomp(ll n)
{
if (n == 1)
return;
if (MR(n))
{
f[cnt++] = n;
return;
}
ll d = n, c = n-1;
while (d == n)
d = PR(n, c--);
do
{
n /= d;
}
while (!(n%d));
decomp(d);
decomp(n);
}
int main()
{
srand(time(0));
ll n;
while (scanf("%lld", &n), n)
{
cnt = 0;
decomp(n);
std::sort(f, f+cnt);
cnt = std::unique(f, f+cnt)-f;
ll ans = n;
for (int i = 0; i < cnt; ++i)
{
// printf("%lld\n", f[i]);
ans = ans/f[i]*(f[i]-1);
}
printf("%lld\n", ans);
}
return 0;
}