2020.8.14【算协集训】欧拉函数专题

网页链接:传送门
密码:HPUACM

A - Relatives (POJ-2407)

Given n, a positive integer, how many positive integers less than n are relatively prime to n? Two integers a and b are relatively prime if there are no integers x > 1, y > 0, z > 0 such that a = xy and b = xz.
Input
There are several test cases. For each test case, standard input contains a line with n <= 1,000,000,000. A line containing 0 follows the last case.
Output
For each test case there should be single line of output answering the question posed above.

Sample InputSample Output
7
12
0
6
4

欧拉函数的模板题

#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const ll maxn=1e6+10;

ll euler(ll n)
{
	ll ans=n;
	for(ll i=2;i<=sqrt((double)n);i++)
	{
		if(n%i==0)
		{
			ans=ans/i*(i-1);
			while(n%i==0)
				n/=i;
		}
	}
	if(n>1)	ans=ans/n*(n-1);
	return ans;
}

int main()
{
	ll n;
	while(~scanf("%lld",&n))
	{
		if(n==0)	break;
		printf("%lld\n",euler(n));
	}
	return 0;
}

B - Primitive Roots (POJ-1284)

We say that integer x, 0 < x < p, is a primitive root modulo odd prime p if and only if the set { (xi mod p) | 1 <= i <= p-1 } is equal to { 1, …, p-1 }. For example, the consecutive powers of 3 modulo 7 are 3, 2, 6, 4, 5, 1, and thus 3 is a primitive root modulo 7.
Write a program which given any odd prime 3 <= p < 65536 outputs the number of primitive roots modulo p.
Input
Each line of the input contains an odd prime numbers p. Input is terminated by the end-of-file seperator.
Output
For each p, print a single number that gives the number of primitive roots in a single line.

Sample InputSample Output
23
31
79
10
8
24

题目让求一个奇素数的原根的个数

根据百度百科的定义:① 如果 p p p 为素数,那么素数 p p p 一定存在原根;② 当模 p p p 有原根时,它有 φ ( φ ( p ) ) φ(φ(p)) φ(φ(p)) 个原根。那么对于素数p的原根的个数为 φ ( p − 1 ) φ(p−1) φ(p1)

  1. 第一种方法(不打表)

    #include<cstdio>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const ll maxn=1e6+10;
    
    ll euler(ll n)
    {
    	ll ans=n;
    	for(ll i=2;i<=sqrt((double)n);i++)
    	{
    		if(n%i==0)
    		{
    			ans=ans/i*(i-1);
    			while(n%i==0)
    				n/=i;
    		}
    	}
    	if(n>1)	ans=ans/n*(n-1);
    	return ans;
    }
    
    int main()
    {
    	ll n;
    	while(~scanf("%lld",&n))
    	{
    		printf("%lld\n",euler(n-1));
    	}
    	return 0;
    }
    
  2. 第二种方法(打表)

    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const ll maxn=1e6+10;
    
    ll m=0,prime[maxn],phi[maxn];
    bool isprime[maxn];
    
    void euler()
    {
    	phi[1]=1;
    	for(int i=2;i<maxn;i++)
    	{
    		if(!isprime[i])
    		{
    			prime[++m]=i;
    			phi[i]=i-1;
    		}
    		for(int j=1;i*prime[j]<maxn && j<=m;j++)
    		{
    			isprime[i*prime[j]]=true;
    			if(i%prime[j]==0)
    			{
    				phi[i*prime[j]]=phi[i]*prime[j];
    				break;
    			}
    			phi[i*prime[j]]=phi[i]*(prime[j]-1);
    		}
    	}
    }
    
    int main()
    {
    	euler();
    	ll n;
    	while(~scanf("%lld",&n))
    	{
    		printf("%lld\n",phi[n-1]);
    	}
    	return 0;
    }
    

C - Visible Lattice Points (POJ-3090)

A lattice point (x, y) in the first quadrant (x and y are integers greater than or equal to 0), other than the origin, is visible from the origin if the line from (0, 0) to (x, y) does not pass through any other lattice point. For example, the point (4, 2) is not visible since the line from the origin passes through (2, 1). The figure below shows the points (x, y) with 0 ≤ x, y ≤ 5 with lines from the origin to the visible points.

Write a program which, given a value for the size, N, computes the number of visible points (x, y) with 0 ≤ x, y ≤ N.
Input
The first line of input contains a single integer C (1 ≤ C ≤ 1000) which is the number of datasets that follow.
Each dataset consists of a single line of input containing a single integer N (1 ≤ N ≤ 1000), which is the size.
Output
For each dataset, there is to be one line of output consisting of: the dataset number starting at 1, a single space, the size, a single space and the number of visible points for that size.

Sample InputSample Output
4
2
4
5
231
1 2 5
2 4 13
3 5 21
4 231 32549

题意:给出范围为(0, 0)到(n, n)的整点,你站在原点处,问有多少个整点可见。
对于点(x, y), 若g = gcd(x, y) > 1,则该点必被点(x/g, y/g)所挡住。因此所见点除了(1, 0)和(0, 1),满足横纵坐标互素。

#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=1e6+10;

ll m=0,prime[maxn],phi[maxn];
bool isprime[maxn];

void euler()
{
	phi[1]=1;
	for(int i=2;i<maxn;i++)
	{
		if(!isprime[i])
		{
			prime[++m]=i;
			phi[i]=i-1;
		}
		for(int j=1;i*prime[j]<maxn && j<=m;j++)
		{
			isprime[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}

int main()
{
	euler();
	int T,n;
	ll ans;
	scanf("%d",&T);
	for(int i=1;i<=T;i++)
	{
		ans=0;
		scanf("%d",&n);
		for(int j=2;j<=n;j++)
			ans+=phi[j];
		printf("%d %d %lld\n",i,n,3+2*ans);
	}
	return 0;
}

D - The Euler function (HDU-2824)

The Euler function phi is an important kind of function in number theory, (n) represents the amount of the numbers which are smaller than n and coprime to n, and this function has a lot of beautiful characteristics. Here comes a very easy question: suppose you are given a, b, try to calculate (a)+ (a+1)+…+ (b)
Input
There are several test cases. Each line has two integers a, b (2<a<b<3000000).
Output
Output the result of (a)+ (a+1)+…+ (b)

Sample InputSample Output
3 1003042
#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=3e6+10;

ll m=0,prime[maxn],phi[maxn];
bool isprime[maxn];

void euler()
{
	phi[1]=1;
	for(int i=2;i<maxn;i++)
	{
		if(!isprime[i])
		{
			prime[++m]=i;
			phi[i]=i-1;
		}
		for(int j=1;i*prime[j]<maxn && j<=m;j++)
		{
			isprime[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
	for(int i=2;i<maxn;i++)
		phi[i]+=phi[i-1];
}

int main()
{
	euler();
	int a,b;
	while(~scanf("%d%d",&a,&b))
	{
		printf("%lld\n",phi[b]-phi[a-1]);
	}
	return 0;
}

E - 找新朋友 (HDU-1286)

新年快到了,“猪头帮协会”准备搞一个聚会,已经知道现有会员N人,把会员从1到N编号,其中会长的号码是N号,凡是和会长是老朋友的,那么该会员的号码肯定和N有大于1的公约数,否则都是新朋友,现在会长想知道究竟有几个新朋友?请你编程序帮会长计算出来。
Input
第一行是测试数据的组数CN(Case number,1<CN<10000),接着有CN行正整数N(1<n<32768),表示会员人数。
Output
对于每一个N,输出一行新朋友的人数,这样共有CN行输出。

Sample InputSample Output
2
25608
24027
7680
16016
#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=1e6+10;

ll m=0,prime[maxn],phi[maxn];
bool isprime[maxn];

void euler()
{
	phi[1]=1;
	for(int i=2;i<maxn;i++)
	{
		if(!isprime[i])
		{
			prime[++m]=i;
			phi[i]=i-1;
		}
		for(int j=1;i*prime[j]<maxn && j<=m;j++)
		{
			isprime[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}

int main()
{
	euler();
	int T,n;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		printf("%lld\n",phi[n]);
	}
	return 0;
}

F - Farey Sequence (POJ-2478)

The Farey Sequence Fn for any integer n with n >= 2 is the set of irreducible rational numbers a/b with 0 < a < b <= n and gcd(a,b) = 1 arranged in increasing order. The first few are
F2 = {1/2}
F3 = {1/3, 1/2, 2/3}
F4 = {1/4, 1/3, 1/2, 2/3, 3/4}
F5 = {1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5}
You task is to calculate the number of terms in the Farey sequence Fn.
Input
There are several test cases. Each test case has only one line, which contains a positive integer n (2 <= n <= 106). There are no blank lines between cases. A line with a single 0 terminates the input.
Output
For each test case, you should output one line, which contains N(n) ---- the number of terms in the Farey sequence Fn.

Sample InputSample Output
2
3
4
5
0
1
3
5
9
#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=1e6+10;

ll m=0,prime[maxn],phi[maxn];
bool isprime[maxn];

void euler()
{
	phi[1]=1;
	for(int i=2;i<maxn;i++)
	{
		if(!isprime[i])
		{
			prime[++m]=i;
			phi[i]=i-1;
		}
		for(int j=1;i*prime[j]<maxn && j<=m;j++)
		{
			isprime[i*prime[j]]=true;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}

int n;
ll sum[maxn];

int main()
{
	euler();
	sum[1]=0;
	for(int i=2;i<maxn;i++)
		sum[i]=sum[i-1]+phi[i];
	while(~scanf("%d",&n))
	{
		if(n==0)	break;
		printf("%lld\n",sum[n]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值