题解:CF2077D Maximum Polygon
CF2077D Maximum Polygon
这题为啥
考虑一个简单的形式,当固定子序列中出现的最大数为
有一个贪心是这样的:将序列中大于
我们可以用单调栈预处理出每个数右边第一个大于它的数的位置。然后我们将序列从左往右扫,对于每一个
但我们在变换过程中也要维护当前子序列是否合法。由于去掉了很多数,我们还要保证
感性理解下这个贪心的正确性,我们从前往后地删数,保证使字典序尽量的大。
于是我们可以通过这个贪心
我们考虑从大到小固定
然后大脑深度思考一下,可以发现这样一个性质:
若以
感性证明一下,有的地方可能不太严谨:
令
反过来的证明仍然是类似的,这里不再赘述。
因此,我们从大到小去确定
那么就做完了,单次贪心复杂度
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+5;
int t,n,a[N],c[N],len,pl[N],mx,suf[N];
struct number{
int num,pl;
} b[N];
bool cmp(number x,number y){
if(x.num==y.num)return x.pl<y.pl;
return x.num>y.num;
}
bool vis[N];
vector<int> ans,nw;
bool dayu(){
if(ans.empty())return 1;
int mi=min(ans.size(),nw.size());
for(int i = 0;i<mi;++i){
if(nw[i]>ans[i])return 1;
else if(nw[i]<ans[i])return 0;
}
return ans.size()<nw.size();
}
stack<int> st;
void getxl(){
len=mx=0;
for(int i = 1;i<=n;++i){
if(!vis[i])c[++len]=a[i],mx=max(mx,a[i]);
}
while(!st.empty())st.pop();
suf[len+1]=0;
for(int i = len;i;--i)pl[i]=-1,suf[i]=suf[i+1]+c[i];
for(int i = len;i;--i){
while(!st.empty() && c[i]>=c[st.top()])st.pop();
if(!st.empty())pl[i]=st.top();
st.push(i);
}
mx<<=1,nw.clear();
if(mx>=suf[1])return ;
int sum=0;
for(int i = 1;i<=len;++i){
nw.push_back(c[i]),sum+=c[i];
if(pl[i]==-1)continue;
sum-=c[i];
if(mx<sum+suf[pl[i]]){
nw.pop_back();
i=pl[i]-1;
}else sum+=c[i];
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>n;
for(int i = 1;i<=n;++i){
cin>>a[i];
b[i]={a[i],i},vis[i]=0;
}
sort(b+1,b+n+1,cmp);
int lim;
ans.clear();
for(int lst=1;lst<=n;++lst){
getxl();
if(nw.empty()){
mx=b[lst].num>>1;
while(b[lst].num>mx&&lst<=n){
vis[b[lst].pl]=1,++lst;
}
--lst;
continue;
}
if(dayu())ans=nw;
mx>>=2;
while(b[lst].num>mx&&lst<=n){
vis[b[lst].pl]=1,++lst;
}
--lst;
}
if(ans.empty())cout<<"-1\n";
else{
cout<<ans.size()<<'\n';
for(auto f:ans)cout<<f<<' ';
cout<<'\n';
}
}
return 0;
}