两数a,b同余m,显然(a-b)%m=0.....若有m%p=0...那么(a-b)%p=0....
将所有的(a[j]-a[i])记录下来...用c[1000000]的表来记...如果一个数p是N对数的同余..那么c[p]=N...
有了上面的处理,就可以方便的统计出对于当前枚举的md...会产生多少对同余的(将md所有的整数倍c[ ] 加起来)...
但产生了N对同余的..并不代表要去除N-1个数才行...比如...
3,6,9,10....(3,6),(3,9),(3,12),(6,9),(6,12),(9,12)...如果当前测试的md=3..那么会有6对同余3的....而实际上最少减去3个数可以保证不出现同余3的情况...
我做到这里就没想法了...
看了下别人的代码.. 自己理解了下..很有道理...不过也感觉很大胆...
其实并不是用md求同余对来计算最少要减去几个数..而是用其剪枝..然后再暴力查找(纯暴力..一个个试..看有多少重复..重复个数是否不大于k)
剪枝的方式是当前md的同余对>k*(k+1)/2..就找下一个md....
为什么同余对>k*(k+1)/2时就不必要用暴力的方式来判断了?
考虑一个极端的情况..给的n个数每一个都是md的整数倍..那么显然就有n*(n-1)/2个关于md的同余对...但是只需要去掉n-1个数就可以使得没有同余对了...
把n-1看成题目要求的k...那么极端情况不就是md的同余对为(k+1)*k/2吗?当md的同余对>(k+1)*k/2,无论如何也要删去k+1个数才能使得没有对于md的同余对出现...
这个剪枝相当劲爆..虽然每个通过了同余对<=(k+1)*k/2验证的md都要进行一次暴力查找判断...但时间完全ok...
Program:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#define ll long long
#define oo 1000000000
using namespace std;
int a[5005],c[1000005],n;
bool used[1000005];
int main()
{
int i,j,k,m;
while (~scanf("%d%d",&n,&k))
{
for (i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
memset(c,0,sizeof(c));
for (i=1;i<n;i++)
for (j=i;j<=n;j++)
c[a[j]-a[i]]++;
for (i=1;i<=a[n]+1;i++)
{
m=0;
for (j=i;j<=1000000;j+=i)
{
m+=c[j];
if (m>k*(k+1)/2) goto A;
}
memset(used,false,sizeof(used));
m=0;
for (j=1;j<=n;j++)
{
if (used[a[j]%i]) m++;
used[a[j]%i]=true;
if (m>k) goto A;
}
break;
A: ;
}
printf("%d\n",i);
}
return 0;
}