codeforces 303C. Minimum Modular(数论+暴力+剪枝+贪心)

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 ≤ 10^6).

Output

Print a single positive integer — the minimum m.

题目大意:给你n个数,你可以删掉k个,求最小的m,使得对任意i,j(i≠j)均有a[i]、a[j]对m不同余(好像不是这么表述的意思差不多就行了)

思路:从小到大枚举答案,若能成为答案则输出。那么如何判断是否答案呢?只须把n个数都求余映射到0~m的区域中,若重复肯定要删,若要删超过k次则不能成为答案。这样做大体的思路就出来了,但是算法复杂度有点大,这么做目测要跪(其实我翻过别人的TLE代码没有剪枝哈哈哈)。所以我们须要进行剪枝,具体方法为:先算出每对a[i]、a[j]的差值,存入di[]数组中,枚举答案ans的时候,差值为ans的数的余数必然有重复,这些数要删掉,若重复的数目大于k(k+1)/2,那么剪掉,因为k次删除无法得出答案。

 剪枝证明:若把abs(a[j]-a[i]) == ans的看成一条边,那么就是给n条边的最小覆盖集(每条边至少有一个点要被删除)。若最多能删k个点,最多能有多少条边呢?任意选k+1个点,最多可以连k(k+1)/2条边,恰好删除k个点。注意到k很小,所以此剪枝效果应该不差。

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 #define MAXN 1000010
 5 
 6 int a[MAXN], di[MAXN], vis[MAXN];
 7 int n, k;
 8 
 9 int check(int m){
10     int cnt = 0;
11     for(int i = 0; i < n; ++i){
12         if(vis[a[i]%m] == m && ++cnt > k) return false;
13         vis[a[i]%m] = m;
14     }
15     return true;
16 }
17 
18 int main(){
19     scanf("%d%d",&n,&k);
20     for(int i = 0; i < n; ++i) scanf("%d",&a[i]);
21     std::sort(a, a+n);
22     int m = a[n-1] + 1;
23     for(int i = 0; i < n; ++i)
24         for(int j = i+1; j < n; ++j)
25             ++di[a[j]-a[i]];
26     int ans;
27     for(ans = 1; ans <= m; ++ans){
28         int cnt = 0;
29         for(int j = ans; j < m; j += ans) cnt += di[j];
30         if(cnt <= k*(k+1)/2 && check(ans)) break;
31     }
32     printf("%d
", ans);
33     return 0;
34 }
View Code
原文地址:https://www.cnblogs.com/oyking/p/3174717.html