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: .
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).
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很小,所以此剪枝效果应该不差。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n", ans); 33 return 0; 34 }