[COCI2007-2008#5] AVOGADRO
题目大意
给你三个长度为 $n$ 的序列(以下我称为 $a,b,c$ 这三个序列),要求:最少删除多少列之后使得在 $a$,$b$,$c$ 三个序列中,每个数字出现的次数相等。
贪心思路
在输入时用桶给每个序列记个数(以下我用 $ca$,$cb$,$cc$ 表示),然后在遍历 $a$ 序列时,如果这个数 $a$ 有,但是 $b$ 或者 $c$ 没有,就得删除。
删除是一整列的删,要把这 3 个数在 $a$,$b$,$c$ 中出现的次数减去。
要注意的是:一列里可能会有本身就合法的数,为了删去不合法的数,这些合法的也会被删去,使得 3 个序列还是不相同。怎么办呢?只能继续删。
所以我们进行多次删除。其实很简单,无脑重复很多次次上述遍历数组 $a$ 的操作,知道遍历一次数组不会再发生删除操作。
这道题就解决了。
Code
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
int n, ans, a[N], b[N], c[N], ca[N], cb[N], cc[N];
int main()
{
// freopen("table.in", "r", stdin);
// freopen("table.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &a[i]);//输入并给a数组计数
ca[a[i]] ++ ;
}
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &b[i]);//输入并给b数组计数
cb[b[i]] ++ ;
}
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &c[i]);//输入并给c数组计数
cc[c[i]] ++ ;
}
int temp = 100;
while (temp -- )//重复执行100次,反复确认
{
for (int i = 1; i <= n; i ++ )//遍历a数组
{
if (a[i] != -1 && (cb[a[i]] == 0 || cc[a[i]] == 0))//如果这个数在a数组中没被删掉并且在b和c数组中没有出现,就要删除
{
ca[a[i]] -- ;
cb[b[i]] -- ;
cc[c[i]] -- ;
a[i] = -1;
}
}
}
for (int i = 1; i <= n; i ++ ) ans += (a[i] == -1);//如果这个数被删除了,ans ++
printf("%d\n", ans);
return 0;
}
如果还不懂可以私聊我。