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;

}

  

你可能感兴趣的:(ini)