C Queries for the Array
题目链接:https://codeforces.com/contest/1861/problem/C
思路:
我们采用2个变量 c n t 0 , c n t 1 cnt_0,cnt_1 cnt0,cnt1,分别记录当前序列未排序的长度,和排序的长度,依次更新这两变量的值,这里我们认为一个未排序的序列只有最后一个数是混乱的(3 4 5 6 2/4 5 6 8 2)。
代码演示:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 10;
const int P = 131; //转换成P进制
int n;
string str;
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
cin>>str;
int cnt0=0,cnt1=1; //当前未排序的长度,已排序的长度
bool flag=false;
int len=0; //序列长度
for(int i=0; i<str.size(); i++) {
if(str[i]=='+') len++;
if(str[i]=='-') {
len--;
if(cnt0>len) cnt0=0;
//我们认为未排序的情况是最后一个数是乱的即(3 4 5 6 4/5 6 7 2)
if(cnt1>len) cnt1=max(1,len);
//更新排序的长度
}
if(str[i]=='1') {
if(cnt0==0) { //如果存在未排序的序列
cnt1=max(1,len);
}
else {
flag=true;
break;
}
}
if(str[i]=='0') {
if(cnt1>=len) { //这种情况已经把len<2的情况包括了
flag=true;
break;
}
else {
if(cnt0==0) cnt0=len;
}
}
}
if(flag) cout<<"NO\n";
else cout<<"YES\n";
}
return 0;
}
D:Sorting By Multiplication
题目链接:https://codeforces.com/contest/1861/problem/D
思路:
其实我们可以看出,对于一个序列来说,让其变为严格递增序列的次数就是序列中 a i ≤ a i + 1 a_i \le a_{i+1} ai≤ai+1的对数,同理,变为严格递减序列的次数就是 a i + 1 ≤ a i a_{i+1} \le a_i ai+1≤ai的对数,由题意可知,我们可以让 [ l , r ] [l,r] [l,r]这个区间乘一个负数,这就意味着我们可以让一个严格递减序列经过一次操作就变为严格递增序列。这样的话,我们可以分为两段,一段严格递减,一段严格递增,枚举递减和递增的分界点,这里我们要注意的是,我们必须选择让前面是递减的,后面的递增的,如果后面选择递减的话,我们将其反转,最后都会变成负数。
代码演示:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 10;
const int P = 131; //转换成P进制
int t,n;
ll a[N];
int 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];
ll b[N];
b[n+1]=b[n]=0; //初始化
for(int i=n-1; i>=1; i--) { //前缀和预处理,要让后面都变成递增的需要多少次
if(a[i]>=a[i+1]) b[i]=b[i+1]+1;
else b[i]=b[i+1];
}
ll t=0,ans=b[1],pre=INF;
for(int i=1; i<=n; i++) { //枚举节点
if(a[i]>=pre) t++; //让前i个数变成递减所需要的次数
pre=a[i];
ans=min(ans,b[i+1]+1+t);
}
cout<<ans<<"\n";
}
return 0;
}