题目链接:
Problem - C - Codeforces
题目大意:
给定一个数组a.问是否存在x,使得gcd(ai+x,aj+x)=1 对任意(1<=x<j<=n)成立
思路:
首先不难发现,数组不可以出现相同的数字
记bi=ai+x
要满足gcd(bi,bj)=1 对任意(1<=x<j<=n)成立,那么对于任意质数p,p至多只可以整除一个bi.否则就会出现gcd(bi,bj)=p的情况。
问题可以转化为判断:任意x的取值,是否都存在质数p可以整除两个bi。
* 对于一个质数p,假设 ,那么
那么思路就很明显了
对于每个质数p,记录a[i]%p的个数,如果cnt[0]~cnt[p-1]都大于2的话。根据*,可知x无解。
根据容斥原理只需要判断(2-n/2) 之间的质数即可。因为对于大于n/2的质数一定存在cnt[i]<2
Code:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
#include<unordered_map>
using namespace std;
#define fi first
#define se second
#define PII pair<int,int>
#define V vector<int>
#define endl "\n"
typedef long long ll;
typedef unsigned long long ull;
const int N=110;
ll a[N];
int t[N];
void solve()
{
int n,f=0;
map<ll,int> mp;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(mp.count(a[i])) f=1;
mp[a[i]]=1;
}
if(f) {cout<<"NO\n"; return ;}
int mi;
for(int mod=2;mod<=n/2;mod++)
{
mi=100;
memset(t,0,sizeof t);
for(int i=1;i<=n;i++)
t[a[i]%mod]++;
for(int i=0;i<mod;i++)
mi=min(mi,t[i]);
if(mi>=2) f=1;
}
if(f) cout<<"NO\n";
else cout<<"YES\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int test;
cin>>test;
while(test--) solve();
return 0;
}
细心的小伙可能就会问了,不是遍历2-n/2的所有质数吗,代码中直接枚举,对于非质数的判断会不会影响结果吗?
大可不必担心,根据质数分解定理一个合数必然可以分解为一些质数的乘积。
以6为例,6可以分解为2*3。假设6满足x无解的条件,即min(cnti)>=2.
,则可以推出 (0<=i<2) 即2也满足x无解的条件,3也是同理 。