Description
给定n个正整数,从中挑出k个数,满足:存在某一个m(m>=2),使得这k个数模m的余数相等。
求出k的最大值,并求出此时的m。如果有多组解使得k最大,你要在此基础上求出m的最大值。
Input
第一行一个正整数n(2<=n<=10^5)。
第二行n个正整数wi。保证不会出现所有w[i]都相等的情况。
Output
一行两个整数k,m。保证答案存在。
Sample Input
6
7 4 10 8 7 1
Sample Output
5 3
HINT
Source
这题好厉害呀QAQ
首先可以发现答案k最小也得是
n2
,感觉可以用奇怪的姿势乱搞?但是我的姿势水平并不足够想出正确的乱搞算法
然后就翻了zky的提交记录和Claris的题解QAQ
因为答案最小是
n2
,所以这就意味着一个数至少也有
12
的概率在被选中的k个数里,所以可以设计一个随机+Hash的做法.
每次随机找一个数
ai
,将这个数作为必选的k个数之一,然后用其他数对其作差,对差值分解质因数.
我们考虑找出分解出的质因数里出现次数最多的那个数,每个数我们都可以看成是拆分为 ai+delta ,考虑对取模后的结果得贡献 ai 部分都是一样的,然后 delta 有相同质因数的,对那个质因数取模后贡献是一样的(0),所以出现次数最多的那个质因数的出现次数再加上 ai 出现的次数就是最优情况下的k.
对于那个固定的k找一个m,只需要把那些找到的所有对应位置的因数乘一下,然后看一看总共出现过哪些结果,找到最小的那个.
对于数目的统计,可以对每个数给一个随机hash值,异或起来求出hash值,然后排序扫一遍.
如果你觉得我写的口胡根本看不懂的话..Claris题解传送门
你也可以直接从QQ上找Claris问.(我怕我口胡错掉QAQ)
最后,今天是3.30,蓝月亮lct1999的生日,代码里粗线了奇怪的东西!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100010
#define MAXV 10000010
#define SIZE 700000
#define GET (ch>='0'&&ch<='9')
using namespace std;
int n,k,m,cnt,tp,T;
int a[MAXN],b[MAXN],maxn;
bool not_prime[MAXV];
int prime[SIZE],top,id[MAXV],fac[MAXV];
int vis[SIZE],sta[40],pow;
int pos[SIZE],lst[SIZE];
struct happy_birthday_lct1999
{
int cnt,hash,num;
happy_birthday_lct1999(){ hash=cnt=0;num=1; }
happy_birthday_lct1999(int Cnt,int Hash,int Num) { cnt=Cnt;hash=Hash;num=Num; }
inline bool operator <(const happy_birthday_lct1999 &a)const { return hash<a.hash; }
}s[SIZE];
inline void in(int &x)
{
char ch=getchar();x=0;
while (!GET) ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();
}
void check()
{
for (int i=2;i<=maxn;++i)
{
if (!not_prime[i]) prime[++top]=i,fac[i]=i,id[i]=top;
for (int j=1;j<=top&&i*prime[j]<=maxn;++j)
{
fac[i*prime[j]]=prime[j];id[i*prime[j]]=j;not_prime[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
}
void solve(int x,int y)
{
int tmp=0,t=0;
for (int i=1;i<=pow;++i) vis[sta[i]]=0;pow=0;
for (;x!=1;vis[id[x]]*=fac[x],x/=fac[x]) if (!vis[id[x]]) vis[sta[++pow]=id[x]]=1;
for (int i=1;i<=pow;++i)
{
tmp=vis[sta[i]];
if (lst[sta[i]]!=T) lst[sta[i]]=T,s[t=pos[sta[i]]=++tp]=happy_birthday_lct1999(0,0,tmp);
else t=pos[sta[i]];
++s[t].cnt;s[t].hash^=y;s[t].num=min(s[t].num,tmp);
}
}
int main()
{
in(n);s[0].hash=-1;
for (int i=1;i<=n;i++)
{
in(a[i]);maxn=max(maxn,a[i]);
while (!b[i]) b[i]=rand();
}
check();
for (T=1;T<=4;++T)
{
int x=a[rand()%n+1],i,j=0;cnt=tp=0;
for (i=1;i<=n;i++)
if (a[i]!=x) solve(max(a[i]-x,x-a[i]),b[i]);
else cnt++;
sort(s+1,s+tp+1);
for (int i=1;i<=tp;++i)
if (s[i].hash!=s[j].hash)
{
if (j)
{
if (s[j].cnt+cnt>k) k=s[j].cnt+cnt,m=s[j].num;
else if (s[j].cnt+cnt==k&&s[j].num>m) m=s[j].num;
}
j=i;
}
else s[j].num*=s[i].num;
if (s[j].cnt+cnt>k) k=s[j].cnt+cnt,m=s[j].num;
else if (s[j].cnt+cnt==k&&s[j].num>m) m=s[j].num;
}
printf("%d %d\n",k,m);
}