总结:
temp个不同的值, 每个值都有小于等于k个,那么对这temp *k个数不断的按顺序标注1~k的话那么就不会导致同一个值有两个相同的标注情况。
如果一个值有大于k个,那么按照1~k去标注肯定会存在重复。
题目链接:https://codeforces.com/contest/1551/problem/B2
题目:
有一个元素是整数的数列,有k个颜色去涂这些元素
求涂色方案,需满足以下条件
(1)每一个元素都可以涂成一种颜色或者不涂;
(2)要求数值一样的元素不能涂相同颜色;
(3)并且k个颜色分别涂的总数量要相等
(4)在此基础上我们的方案是让涂色的元素数量最大,可能会有多种方案,输出一种
分析:
1.首先,根据题目的要求可以知道,当某个值出现了k次以上,则k次以上的部分就无法涂上颜色(因为(2)中说了,数值一样的元素不同涂相同的颜色,而不同的颜色最多只能有k个)。而无法涂上颜色的我们用0进行标注。
这样就使得(2)的要求得到了满足
2.随后,我们统计一下还有多少个值没有被标注,求出它们的总和,如果总和(total)不是 k 的倍数,则删去掉多出的部分(total % k)。 为什么要删掉 total % k 个呢 ? 因为我们按照题目的要求,k个颜色,并且每个颜色所涂的块数要相同,所以所能涂的颜色最多也就是 k 的倍数。多出的部分必然不能够涂。
于是又有一个问题,即然要删掉total % k 个块, 那么删掉哪些块呢?
实际上在剩下的块中,随便删 total % k 个块都可以。
因为我们经过了操作1以后,所有的值都不会出现超过k的情况,那么所有值都可以通过从1~k顺序赋值的方式赋值,并且不会出现重复。
如值为1的块现在还有x1个,值为2的块现在还有x2个,值为3的块现在还有x3个。
而x1 < k , x2 < k , x3 < k.
那么先将x1个 从1~k不断赋值,在对x2不断赋值,在对x3不断赋值,所以不会出现重复的情况。(从而随便删去total % k个块都可以)。
这样就使得(3)的条件得到了满足。
3.随后排序,按照顺序标注1~k的颜色即可。
举例:
举例来说,k为3的话:
1 1 1 2 2
所以最多涂3个。 如1 , 1 , 1涂3种颜色
1 1 1 2 2 2 全部都可以涂。
同样1 1 1 2 2 3也一样可以涂
1 1 1 2 2 3 4 这时,4就涂不了
1 1 1 1 2 2 2这时,多出的1就应该删去。
代码实现:
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int N = 2e5 + 10;
struct Node
{
int v;
int idx;
}edgs[N];
int a[N]; // 用于统计这个值出现了多少次了,如果超过了k次,则后面的不用上颜色了
int book[N]; // 用于标记颜色从0~k
bool cmp(struct Node a , struct Node b)
{
return a.v < b.v;
}
int main()
{
int loop;
scanf("%d",&loop);
while(loop--)
{
memset(book,-1,sizeof book); //先让book的颜色为-1,因为后面会对他进行0~k的赋值
memset(a,0,sizeof a); // 清空a
int n,k;
scanf("%d %d",&n,&k);
for(int i = 1 ; i <= n ; i++)
{
int temp;
scanf("%d",&temp);
edgs[i].v = temp;
edgs[i].idx = i;
if(a[temp] == k)
{
book[i] = 0; // 给当前这个i节点上0,即不上色。因为已经有k个temp值了,其他的值上不了颜色了。
}
else
{
a[temp]++;
}
}
sort(edgs + 1 ,edgs + 1 + n, cmp);
int cnt = 0;
for(int i = 1 ; i <= n ; i++)
{
if(book[i] == -1)
{
cnt++;
}
}
if(cnt % k) // 如果剩下的总值不能够整除k的话,就删去cnt % k个
{
int temp = cnt % k;
int d = 1; // 下标
while(temp) // 接下来要删除cnt % k个,从尾巴或者从开头都可以
{
if(book[edgs[d].idx] == -1) // 还没有上颜色
{
book[edgs[d].idx] = 0;
temp--;
}
d++;
}
}
int color = 1; // 接下来开始从1到k涂颜色
for(int i = 1 ; i <= n ; i++)
{
if(book[edgs[i].idx] == -1)
{
book[edgs[i].idx ] = color++;
}
if(color == k + 1) // 准备用第k + 1 种颜色了,那就变回颜色1
{
color = 1;
}
}
for(int i = 1 ; i <= n ; i++)
{
printf("%d ",book[i]);
}
printf("\n");
}
return 0;
}