题目链接: http://codeforces.com/contest/1163/problem/B2
题意: 给你N个数,现求满足给定的前i个数中,选择去掉其中的一个,能使得剩余的数字出现的次数都相同的最大i。比如给你3 2 1 1 4 5 1七个数,那么假如i = 4,那就是3 2 1 1四个数,我可以去掉一个1,那么3、2、1三个数字出现的次数就都是1次了。
题解: 如果是前面的easy edition可以用暴力,但是这里
1
≤
n
≤
1
0
5
1≤n≤10^5
1≤n≤105,给的数
1
≤
n
u
m
≤
1
0
5
1≤num≤10^5
1≤num≤105,暴力肯定不行。这里我先记录一个数字 i 出现了几次,用一个a[i]来记录数字 i 出现的次数,再记录出现 i 次的数有几个,用一个b[i]来记录。
这里的情况比较少,要想满足条件,肯定是只有两种出现次数 (假如某三个数分别出现了1、2、3次,那么不管去掉哪个数都不能使所有数出现次数相等),所以这里考虑两种情况,一种是去掉最大的出现次数的一个数就可以平衡(一定是两个相邻的出现次数,比如出现2次和出现3次),一种是去掉最小的出现次数就可以平衡(这里最小的出现次数只能是1,假如出现次数是2,那么去掉一个该数,这个数出现次数就是1,可以看到仍是不满足的)
首先,在满足maxx * b[maxx] + (maxx - 1) * b[maxx - 1] == i的情况下就满足了只有两种出现次数maxx和maxx - 1,同理maxx * b[maxx] + b[1] == i 满足即可说明只有两种出现次数maxx和1。
先看第一种情况,比如1 1 2 2 3 3 3,两种出现次数2和3,其中b[2] = 2, b[3] = 1, 那么显然去掉一个3即可,这里只有多的出现次数b[maxx] = 1才行。
再看第二种情况,比如1 2 2 2 3 3 3, 两种出现次数1和3,其中b[1] = 1, b[3] = 2, 这里去掉1即可, 这里只有满足b[1] = 1才可行。
其中有一种特殊的,就是每个数都只出现了一次,那肯定满足。
代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
const int MAX = 1e5 + 10;
int a[MAX], b[MAX];//a[i]记录数i出现了几次, b[i]记录出现了i次的数有几个
int main() {
int N, ans, x, maxx = -INF;
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
scanf("%d", &x);
a[x]++;//数x出现次数加一
maxx = max(a[x], maxx);//当前出现次数最大
b[a[x]]++;//出现a[x]次++
b[a[x] - 1]--;//出现a[x]-1次--
if (maxx * b[maxx] + (maxx - 1) * b[maxx - 1] == i) {//这个判断条件就满足了只有两种出现次数maxx和maxx - 1(保证相邻)
if (b[maxx] == 1)ans = i;//出现多的次数为1,那就去掉多的
if (maxx == 1)ans = i;//都只出现了一次
}
if (maxx * b[maxx] + b[1] == i) {//两种出现次数maxx和1
if (b[1] == 1)ans = i;//出现少的次数为1,去掉少的
}
}
printf("%d\n", min(ans, N));
return 0;
}