xjtuoj 1151:把你挂在地灵殿门口当装饰品!
恋恋,嘿嘿,恋恋
题意看起来很无意识,实际上这个序列是由一段\(A\)类罪袋+\(BC\)混杂罪袋组合而成,因此可以先找出序列开头的一段连续上升子序列作为\(max(k-m)\)(也就是\(PosA\))
接着考虑\(C\)类罪袋,容易看出\(C\)类罪袋必定是从\(N\)开始递减的一段子序列(倒序了),因此找到\(C\)类罪袋的结束点\(PosC\)
最后是\(B\)类罪袋,已知了\(PosC\)那么只要倒序往前找比\(PosC\)小的值即可,并且更新比较值。当找到大于比较值得数的时候先进行判断,如果此时循环到的序列的\(i\)比\(PosA\)大,那么说明出现了\(ABC\)罪袋都无法取到的值,反之说明找到了\(B\)罪袋的结束点\(PosB\)。接着跳出循环。
最后得到了\(PosB\)和\(PosC\),两者取最小值即是\(min(k-m)\)
代码
#include<bits/stdc++.h>
#define F(i,n,m) for(int i=n;i<m;i++)
#define f(i,n,m) for(int i=n;i>m;i--)
typedef unsigned long long ull;
typedef long long ll;
using namespace std;
inline int read() {
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true;
else
num = c - '0';
while (isdigit(c = getchar()))
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
int zd[200005];
int main() {
std::ios::sync_with_stdio(false);
int n;
n=read();
int posA,posB,posC;
posA=posB=posC=0;
F(i,0,n) zd[i]=read();
F(i,0,n-1) if(zd[i]>zd[i+1]) {
posA=i;
break;
}
int ls=n;
f(i,n-1,-1) if(zd[i]==ls) {
posC=i;
ls--;
}
int flag=1;
f(i,n-1,-1) {
if(zd[i]<zd[posC]) {
if(zd[i]<=ls) {
posB=i;
ls=zd[i];
} else {
if(i>posA)flag=0;
break;
}
}
}
if(flag) cout<<min(posB,posC)<<" "<<posA+1;
else cout<<-1<<" "<<-1;
return 0;
}
咦所以怎么看起来是模拟不是贪心或者二分(