hdu6390 GuGuFishtion(多校7-1005)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38749759/article/details/81665977

GuGuFishtion

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 711    Accepted Submission(s): 270


 

Problem Description

Today XianYu is too busy with his homework, but the boring GuGu is still disturbing him!!!!!!
At the break time, an evil idea arises in XianYu's mind.
‘Come on, you xxxxxxx little guy.’
‘I will give you a function ϕ(x) which counts the positive integers up to x that are relatively prime to x.’
‘And now I give you a fishtion, which named GuGu Fishtion, in memory of a great guy named XianYu and a disturbing and pitiful guy GuGu who will be cooked without solving my problem in 5 hours.’
‘The given fishtion is defined as follow:

                                                           


And now you, the xxxxxxx little guy, have to solve the problem below given m,n,p.’

                                                            


So SMART and KINDHEARTED you are, so could you please help GuGu to solve this problem?
‘GU GU!’ GuGu thanks.

Input

Input contains an integer T indicating the number of cases, followed by T lines. Each line contains three integers m,n,p as described above.
1≤T≤3
1≤m,n≤1,000,000
max(m,n)<p≤1,000,000,007
And given p is a prime.

Output

Please output exactly T lines and each line contains only one integer representing the answer.

Sample Input

1

5 7 23

Sample Output

2

Source

2018 Multi-University Training Contest 7

题目大意就是根据给的公式计算数值,但是如果直接模拟肯定就是TLE,所以借助某位大神的公式推导,然后就可以解出本题目了。本题用到了欧拉函数,莫比乌斯函数,逆元达打表,和gcd的的方法,总的时间复杂度(O(logn))

大佬的推导过程如下(大佬的详细代码https://blog.csdn.net/my_sunshine26/article/details/81635187

补充:

 1、我求a[i]的时候是用逆元的方式求的。

废话不多说直接上代码:

#include<algorithm>
 #include<iostream>
  #include<cstring>
   #include<cstdio>
using namespace std;
typedef long long ll;
const int maxn=1000005;
ll a[maxn];
ll inv[maxn];//逆元
ll prime[maxn];//保存素数
bool vis[maxn];//初始化
ll phi[maxn];//欧拉函数
ll mu[maxn];//莫比乌斯函数值
ll m,n,p;
//自己处理了一下模板,一次性打三个表(欧拉值表,素数表,莫比乌斯函数值表)
//第一个素数下标为0,第一个欧拉值或莫比乌斯函数值下标为1
void Prime()//(NlogN)
{
	ll cnt=0;
	phi[1]=1;
    mu[1]=1;
	for(ll i=2;i<=maxn;i++)
	{
		if(!vis[i])
		{
			prime[cnt++]=i;
			phi[i]=i-1;
			mu[i]=-1;
		}
		for(ll j=0;j<cnt&&i*prime[j]<maxn;j++)
		{
			ll k=i*prime[j];
			vis[k]=1;
			if(i%prime[j]==0)//关键
			{
				phi[k]=phi[i]*prime[j];
				mu[i*prime[j]]=0;
				break;
			}
			else{
				phi[k]=phi[i]*(prime[j]-1);
				mu[i*prime[j]]=-mu[i];
			}
		}
	}
}
void INV() {//逆元打表
    inv[1] = 1;
    for (int i=2; i<=min(m,n); ++i) {
        inv[i] = (ll) (p - p / i)* inv[p%i] % p;//逆元打表递推式
    }
	for(int i=1;i<=min(n,m);i++)
		a[i]=(ll)i*inv[ phi[i] ]%p;
}
ll G(int n,int m)//m,n的定义必须为int型,否则TLE,很迷~~~~~
{
	ll ans=0;
	for(int i=1;i<=min(n,m);i++)
	{
		ans+=(ll)mu[i]*(n/i)*(m/i);
		ans%=p;
	}
	return ans;
}
int main()
{
	Prime();
	int T;
	scanf("%d",&T);
    while(T--)
	{

		scanf("%lld%lld%lld",&m,&n,&p);
		INV();
		ll ans=0;
		for(int i=1;i<=min(m,n);i++)
		{
			ans+=a[i]*G(n/i,m/i);
			ans%=p;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

       

猜你喜欢

转载自blog.csdn.net/qq_38749759/article/details/81665977