您的位置:首页 > 其它

【PA2013】【BZOJ3837】Filary

2016-03-30 11:27 246 查看
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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息