51nod 1217 Minimum Modular(数论+暴力)

  根据抽屉原理显然m>=(n-K)

  于是在[n-K,max(a1..an)+1]的范围中枚举m

  考虑K=0的做法...

  如果a[i]≡a[j](mod m),则有m|(a[i]-a[j]),只要O(n²)记录下所有a[i]-a[j],找在max范围内m的倍数是否出现过就行了。根据调和级数复杂度为O(n²+max log max)

  如果K>0

  我们记录下m的倍数出现过的次数cnt,如果cnt>k*(k+1)/2说明至少有k+1个数模m同余,显然不可行

  如果满足cnt<=k*(k+1)/2,我们求出a[i]%m用数组记录,每种只能保留一个,算一下超过的有多少个,若<=k就可行

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long 
using namespace std;
const int maxn=500010,inf=1e9;
int n,K,mx;
int a[maxn],v[maxn*2],vis[maxn*2];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;
}
int main()
{
    read(n);read(K);
    if(n+1<=K)return puts("1"),0;
    for(int i=1;i<=n;i++)read(a[i]),mx=max(mx,a[i]);
    sort(a+1,a+1+n);
    for(int i=1;i<n;i++)
    for(int j=i+1;j<=n;j++)
    v[a[j]-a[i]]++;
    for(int i=n-K;i<=mx+1;i++)
    {
        int cnt=0;
        for(int j=1;i*j<=mx;j++)
        cnt+=v[i*j];
        if(cnt>(K*(K+1)>>1))continue;
        cnt=0;
        for(int j=1;j<=n;j++)
        {
            int x=a[j]%i;
            if(vis[x]!=i)vis[x]=i;
            else cnt++;
        }
        if(cnt<=K)return printf("%d",i),0;
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Sakits/p/7382350.html