Codeforces 1295D Same GCDs(歐拉函數)

傳送門

題意:給定a,m\le10^{10},若0\le x<m,求有多少個x滿足gcd(a,m)==gcd(a+x,m)

題解:如果滿足gcd相同則x必須爲gcd(a,m)的倍數,設gcd(a,m)=d,a=ud,m=vd,則若0\le w<v,有多個w滿足gcd(u+w,v)==1。因爲d是最大公因數所以gcd(u,v)==1。到這裏(憑藉豐富的騙分經驗?)就可以直接猜一波答案是phi(v)了。所以求個gcd再求個歐拉函數就完事兒。一開始歐拉函數沒寫好還T了一發......這次真的是自己把答案猜對的(*—*)

下面證明一下答案:

相當於要證正整數序列上每個長度爲v的週期內與v互質的數的個數相等並且它們的分佈是和第一個週期[1, v]是相同的。即證gcd(kx+a,x)==1\Leftrightarrow gcd(a,x)==1,然後充分性和必要性都反證一下就好了。

爲什麼證明了與v互質的數的分佈的週期性就好?因爲有了週期性後,可以把詢問的區間進行平移。最後gcd(u+w,v)==10\le w<v就可以轉化爲gcd(x,v)==11\le x \le v

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
ll a,m;
inline ll read() {
	ll x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*f;
}
inline ll gcd(ll a,ll b) {
	return !b?a:gcd(b,a%b);
}
inline ll phi(ll x) {
	ll ret=1;
	for (register ll i=2;i*i<=x;++i)
		if (x%i==0) {
			ll cur=1;
			while (x%i==0) {
				cur*=i;
				x/=i;
			}
			ret*=(i-1)*cur/i;
		}
	if (x>1) ret*=x-1;
	return ret;
}
int main() {
	int kase=read();
	while (kase--) {
		a=read(),m=read();
		ll v=m/gcd(a,m);
		printf("%lld\n",phi(v));
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章