题解:P15321 【MX-X24-T2】「RiOI-7」Oops, It's Yesterday Twice More
Han_Li_2012 · · 题解
闲话
看到
做法
用
注意到只能删数不能加数,所以显然
考虑
- 当
cnt_i >= 3 时用一次操作删掉两个i 。重复操作直到不满足条件。 - 若
cnt_i = 2 ,找到一个不等于i 且可以被删除的数,删除这个数和一个i 。 - 若
cnt_i = 1 ,找到两个大于/小于i 且可以被删除的数,删掉其中一个和i 。 - 最后剩下一些可以删除的数,尽量删除之。
注意一下如果
做完了。
代码
为什么我的代码那么长。
#include <bits/stdc++.h>
using namespace std;
#define pre(i,n) for(int i = n;~i;--i)
#define rep(i,n) for(int i = 1;i <= n;i++)
#define rpt(i,a,n) for(int i = a;i <= n;++i)
#define ll long long
#define swap(x,y) (x ^= y ^= x ^= y)
#define debug cerr<<"Help!\n"
constexpr int N = 1e6 + 5;
int a[N],cnt[N],sum[N],T,n,mx;
inline void work(int i){
#define no return cout<<"-1 ",void();
if(i > mx) no;
int cl = i >= 1 ? sum[i-1] - i : 0,cr = sum[n] - sum[i];
if(i == mx){
cout<<(cl + cr - 1 + (bool)(i ? sum[i-1] ^ i : 0)) / 2<<' ';
return;
}
//from here
int res = cnt[i];
if(cnt[i] >= 3){
res = (cnt[i] - 1) / 2,cnt[i] -= res * 2,res += cnt[i];
}
// to here
if(cl + cr < cnt[i] - 1) no;
int lft = cl + cr - (cnt[i] - 1);
// if(lft + i < 2 || (lft < 2 && !cl) || max(cl + i,cr) < 2) no;
bool f = i ? sum[i-1] ^ i : 0;
if(lft + f < 2 || (lft < 2 && !cl) || max(cl + f,cr) < 2) no;
// int res = cnt[i];
--lft;//还有 lft 个可以删除的数.
cout<<res + (lft - 1 + (bool)(i ? sum[i-1] ^ i : 0)) / 2<<' ';
}
inline void solve(){
rpt(i,0,n + 1) cnt[i] = sum[i] = 0;
cin>>n;
rep(i,n) cin>>a[i],++cnt[a[i]];
sum[0] = cnt[0];
rep(i,n + 1) sum[i] = sum[i-1] + cnt[i];
rpt(i,0,n + 1) if(!cnt[i]){
mx = i;
break;
}
rpt(i,0,n) work(i);
cout<<'\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--) solve();
cerr<<'\n'<<1.0 * clock() / CLOCKS_PER_SEC;
return 0;
}