CF 303C——Minimum Modular——————【剪枝】

Minimum Modular
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You have been given n distinct integers a1, a2, ..., an. You can remove at most k of them. Find the minimum modular m (m > 0), so that for every pair of the remaining integers(ai, aj), the following unequality holds: .

Input

The first line contains two integers n and k (1  ≤ n  ≤ 5000, 0 ≤ k ≤ 4), which we have mentioned above.

The second line contains n distinct integers a1, a2, ..., an (0 ≤ ai ≤ 106).

Output

Print a single positive integer — the minimum m.

Sample test(s)
input
7 0
0 2 3 6 7 12 18
output
13
input
7 1
0 2 3 6 7 12 18
output
7

 

参考:http://www.cnblogs.com/Lyush/archive/2013/05/14/3077258.html

题目大意:给你n个数,你可以从中删除最多k个数,使得剩余的所有数对m取余没有同余的,求最小的m。

解题思路:首先想到暴力,从小到大枚举m,然后判断n个数中对m取模同余个数有多少,如果超出k就枚举更大的m。然而这样的话,时间复杂度为O(n*1e6)。然后在网上找了博客看,但是有些地方当时自己感觉很不好理解的,这里做下自己的解释。1.首先这里用了一个剪枝,这个剪枝能节省大量时间。因为如果有k+1个数都是对m取模同余,那么只需删除k个数,就可以让剩下的数(只剩下一个数)不同余,那么从k+1个同余的数中取出2个数组成同余对的组合数就有C(2,k+1)种,即k*k+1/2种,那么如果对m取模同余的同余对的组合数大于k*k+1/2种,说明无法删除k个数使得剩下的数不同余。2.然后暴力判断此时满足1步骤的m作为模是否能满足同余的数小于k个。

#include<bits/stdc++.h>
using namespace std;
#define max(a,b) (a)>(b)?(a):(b)
const int maxn=1e6+100;
int num[maxn];
int a[5500];
bool flag[maxn];
int dif(int a,int b){
   return  a>b? a-b:b-a;
}
int main(){
    int n,k,i,j,maxa,m,mark,sum,cn,mod;
    maxa=-1;
    while(scanf("%d%d",&n,&k)!=EOF){
        memset(num,0,sizeof(num));
        for(i=0;i<n;i++){
            scanf("%d",&a[i]);
            maxa=max(a[i],maxa);
        }
        //首先应知道a%m==b%m  -->  |a-b|%m==0
        for(i=1;i<n;i++){
            for(j=0;j<i;j++){
                //不同类型的同余对各有多少
                num[dif(a[i],a[j])]++;
            }
        }
        for(m=1;m<=maxa;m++){
            sum=0;
            for(i=m;i<=maxa;i+=m){  
            //这里i+=m的原因是,这样能保证同余对 对于对之间也都是同余的,即这样挑出的组合中所有数都是同余的。
                sum+=num[i];        //
                if(sum>k*(k+1)/2){  //剪枝
                    break;
                }
            }
            if(sum>k*(k+1)/2){
                continue;
            }
            cn=0,mark=0;
            for(j=0;j<n&&(!mark);j++){  //暴力判断m是否满足题目的要求
                mod=a[j]%m;
                if(!flag[mod]){
                    flag[mod]=1;
                }else{
                    cn++;
                    if(cn>k){
                        mark=1;
                    }
                }
            }
            for(j=0;j<n;j++){   //还原
                flag[a[j]%m]=0;
            }
            if(!mark){
                mark=m;
                break;
            }
        }
        printf("%d\n",mark);
    }
    return 0;
}

  

posted @ 2015-06-01 14:17  tcgoshawk  阅读(362)  评论(0编辑  收藏  举报