题意: 给一序列串求最大x 有 x前删除一个值后每个值出现次数相同
解法: B1是小范围版, 只要枚举数字就行
B2用权值线段树记录最大最小出现次数, 出现n次的数有几个, 结合B1的规律(在代码里↓)写即可
代码
/*
Zeolim - An AC a day keeps the bug away
*/
//pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <sstream>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#define max(a, b) a > b ? a : b
#define min(a, b) a > b ? b : a
using namespace std;
//using namespace __gnu_pbds;
//typedef tree <long long, null_type, less <long long>, rb_tree_tag, tree_order_statistics_node_update> rbtree;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 10;
const ll MOD = 1e9 + 7;
int arr[MAXN] = {0}, cnt[MAXN] = {0}, rnt[MAXN] = {0}, num;
struct node
{
int fst, lst, val, mival;
}sgtree[MAXN * 4];
void build(int now, int fst, int lst)
{
sgtree[now].fst = fst, sgtree[now].lst = lst;
if(fst == lst) { sgtree[now].val = 0, sgtree[now].mival = INF; return ; }
int mid = (fst + lst) / 2;
build(now * 2, fst, mid);
build(now * 2 + 1, mid + 1, lst);
sgtree[now].val = max(sgtree[now * 2].val, sgtree[now * 2 + 1].val);
sgtree[now].mival = min(sgtree[now * 2].mival, sgtree[now * 2 + 1].mival);
}
int ask(int now, int fst, int lst)
{
if(fst <= sgtree[now].fst && lst >= sgtree[now].lst) return sgtree[now].val;
int mid = (sgtree[now].fst + sgtree[now].lst) / 2;
int rval = -(1 << 30);
if(fst <= mid) rval = max(rval, ask(now * 2, fst, lst));
if(lst > mid) rval = max(rval, ask(now * 2 + 1, fst, lst));
return rval;
}
int askmi(int now, int fst, int lst)
{
if(fst <= sgtree[now].fst && lst >= sgtree[now].lst) return sgtree[now].mival;
int mid = (sgtree[now].fst + sgtree[now].lst) / 2;
int rval = INF;
if(fst <= mid) rval = min(rval, askmi(now * 2, fst, lst));
if(lst > mid) rval = min(rval, askmi(now * 2 + 1, fst, lst));
return rval;
}
void change(int now, int pos, int rval)
{
if(sgtree[now].fst == sgtree[now].lst) { sgtree[now].val = sgtree[now].mival = rval; return; }
int mid = (sgtree[now].fst + sgtree[now].lst) / 2;
if(pos <= mid) change(now * 2, pos, rval);
else change(now * 2 + 1, pos, rval);
sgtree[now].val = max(sgtree[now * 2].val, sgtree[now * 2 + 1].val);
sgtree[now].mival = min(sgtree[now * 2].mival, sgtree[now * 2 + 1].mival);
}
int main()
{
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);
//freopen("D://test.in", "r", stdin);
//freopen("D://test.out", "w", stdout);
int n, len;
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> arr[i], len = max(len, arr[i]);
build(1, 1, len);
int ans = 0;
//cnt记录 x出现的次数 rnt记录出现 x次的数字有几个 num记录当前一共出现数字个数
for(int i = 1; i <= n; ++i)
{
int x = arr[i];
if(!cnt[x]) ++num;
++cnt[x], ++rnt[cnt[x]];
if(i != 1)
--rnt[cnt[x] - 1];
change(1, arr[i], cnt[arr[i]]);
int mx = ask(1, 1, len), mi = askmi(1, 1, len); //求最大最小值
if(mx == mi && rnt[mx] == 1) ans = i; //就一个数
else if(mx == mi && mi == 1) ans = i; //一堆数但是出现次数都是1
else if(mi == 1 && rnt[1] == 1 && rnt[mx] == num - 1) ans = i; //只有一个数出现一次
else if(mx - mi == 1 && rnt[mx] == 1) ans = i;//最多次比其他都多1
}
cout << ans << '
';
return 0;
}