题目链接
http://codeforces.com/contest/1133/problem/B
题意
有 n n n个盒子,第 i i i个盒子里有 d i di di个糖果,给每个人两个盒子,要求 d i + d j di+dj di+dj能被 k k k整除。
问最多能给多少个盒子。
思路
很容易想到的思路是排序之后枚举,看两个数加起来能否被 k k k整除。但是 n n n范围是 1 0 5 10^5 105,这种 O ( n 2 ) O(n^2) O(n2)的做法显然会超时。
我的做法是,对于每个盒子,求出 d i di di % k k k ,记录在数组 c [ i ] c[i] c[i]中,答案就由两部分组成:
- 对于 k k k的倍数: c [ 0 ] / 2 c[0] / 2 c[0]/2
- 对于不是 k k k的倍数: m i n ( c [ i ] , c [ k − i ] ) min(c[i], c[k - i]) min(c[i],c[k−i])
这里k是奇数和偶数的时候有点不一样,需要注意一下。
AC代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<string>
#include<sstream>
#include<cctype>
#include<map>
#include<stack>
#include<queue>
#include<list>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
const double PI = atan(1.0)*4;
const int INF = 0x7ffffff;
const ll MOD = 1000000007;
const int maxn = 200010;
int a[maxn];
int c[110];
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
int n, k, ans = 0;
scanf("%d%d", &n, &k);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
a[i] = a[i] % k;
c[a[i]]++;
}
ans += c[0] / 2;
for(int i = 1; i < k / 2; i++)
ans = ans + min(c[i], c[k - i]);
if(k % 2 == 0)
ans = ans + c[k / 2] / 2;
else
ans = ans + min(c[k / 2], c[k - k / 2]);
printf("%d\n", ans * 2);
return 0;
}
本文解析了CodeForces竞赛中一道关于盒子里糖果数量的题目,通过优化算法,使用模运算和计数技巧,避免了O(n^2)的时间复杂度,实现了高效的解答。
602

被折叠的 条评论
为什么被折叠?



