兩數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 1000000000using 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;}