Recently Polycarp has opened a blankets store and he faced with many challenges.
He has got k blankets. A blanket has two sides, each of k blankets has at most one colored side. So either both sides are uncolored or one side is colored and the other one is not. If a side is colored, one of n possible colors is used. It is known that k is divisible by n.
Polycarp wants to color all uncolored sides in such a way that:
each blanket will have both sides colored (one color per side), the colors can be the same or different, all the used colors are from n possible colors;
it will be possible to compose n kits with blankets in each kit that blankets in each kit are identically colored.
It is allowed to turn over blankets to determine that they are identically colored: for example, red-blue and blue-red blankets are identically colored. Blankets in different kits can be identically colored.
Input
The first line contains two integer numbers k and n (1 ≤ n ≤ k ≤ 1000) — number of blankets and colors. It is guaranteed that k is divisible by n. The second line contains a sequence of integers c 1, c 2, …, c k (1 ≤ c i ≤ n or c i = - 1), where c i stands for the color of the colored side of the i-th blanket or - 1 if it is uncolored.
Output
If there is no solution for the problem, print “No” in the first line. Otherwise print a line containing “Yes” and k lines describing each blanket. The i-th line should contain a pair of colors (integers in the range 1, 2, …, n) used for the i-th blanket. You may print colors in pairs in any order.
If there are multiple solutions, print any of them.
Examples
Input
6 2
1 1 2 2 -1 2
Output
Yes
1 2
2 1
2 2
2 2
2 1
2 2
Input
8 4
4 -1 1 -1 4 3 -1 -1
Output
Yes
4 1
2 1
2 1
3 1
1 4
3 1
4 1
4 1
题意:
n个卡片,k种颜色,有些卡片有一面有颜色,有些卡片两面都没有颜色。要求你进行涂色,使得将这些卡片分成k组,每组内卡片都相同(意味着卡面两面颜色相同)。
思路:
将所有为-1的卡牌正面涂上颜色k,
同时按照颜色分成k组并进行排序,
那么对于当前数目最小那一组,
- 如果数目大于等于n/k,那么把 n/k 数目的卡牌正反面涂上自己颜色,并去掉。
- 如果数目小于n/k,那么找到最大的一组,补全最小那一组使得其数目大于n/k,并去掉最小这一组。
对于第二步,假设x = n/k,那么当前有k个颜色,总数为x * k,根据鸽巢定理,最大颜色数目至少为x。此时一定满足。
第一轮会消耗掉x个卡牌,并且会消耗掉一个颜色。剩余
个卡牌,剩余
个颜色,同理最大数目至少为x,之后也一定能满足。所以保证一定有解。
AC代码,实现上看了学长的代码,也就是通过vector记录每个颜色对应的卡牌下标。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <queue>
using namespace std;
const int maxn = 10005;
int b[maxn],c[maxn],d[maxn];
vector<int>a[maxn];
int cmp(int x,int y) {
return a[x].size() < a[y].size();
}
int main() {
int n,k;scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i++) {
scanf("%d",&c[i]);
if(c[i] == -1) c[i] = k;
a[c[i]].push_back(i);
}
int k1 = k,k2 = n / k;
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= k1;j++) {
d[j] = j;
}
sort(d + 1,d + 1 + k1,cmp);
int first = -1;
for(int j = 1;j <= k1;j++) {
if(a[d[j]].size() == 0) continue;
first = d[j];
break;
}
if(first == -1) break;
if(a[first].size() > k2) {
for(int j = 1;j <= k2;j++) {
b[a[first].back()] = first;
a[first].pop_back();
}
}
else {
int num = k2 - a[first].size();
for(int j = 1;j <= num;j++) {
b[a[d[k1]].back()] = first;
a[d[k1]].pop_back();
}
for(int j = 0;j < a[first].size();j++) {
b[a[first][j]] = d[k1];
}
a[first].clear();
}
}
printf("Yes\n");
for(int i = 1;i <= n;i++) {
printf("%d %d\n",c[i],b[i]);
}
return 0;
}
WA65的代码,使用map输出(感觉可以啊),并且没有严格使用最大值。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
const int maxn = 1005;
int c[maxn];
map<pair<int,int>,int> b;
struct Node {
int id,v;
}a[maxn];
int cmp(Node a,Node b) {
return a.v < b.v;
}
int main() {
int n,k;scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i++) {
scanf("%d",&c[i]);
if(c[i] == -1) c[i] = k;
a[c[i]].v++;
a[c[i]].id = c[i];
}
int k1 = k,k2 = n / k;
for(int i = 1;i <= k1;i++) {
a[i].id = i;
}
sort(a + 1,a + 1 + k1,cmp);
for(int i = 1;i <= k1;i++) {
if(a[i].v == 0) continue;
if(a[i].v >= k2) {
b[{a[i].id,a[i].id}] += a[i].v / k2 * k2;
a[i].v %= k2;
}
for(int j = k1;j >= i + 1;j--) {
if(a[i].v + a[j].v >= k2) {
int tmp = k2 - a[i].v;
b[{a[j].id,a[i].id}] += tmp;
b[{a[i].id,a[j].id}] += a[i].v;
a[i].v = 0;
a[j].v -= tmp;
break;
}
}
}
printf("Yes\n");
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= k1;j++) {
if(b[{c[i],j}]) {
b[{c[i],j}]--;
printf("%d %d\n",c[i],j);
break;
}
}
}
return 0;
}