B. Nastya and Door
题目大意:
有个长度为n的序列,如果ai>ai-1且ai>ai+1,那么ai即为顶峰,问在给定的区间长度k,求包含最多顶峰的区间数+1,若答案有多个,则取左端点最小,注意:端点不算顶峰
解题思路:
第一种方法:前缀和
把每个顶点标记出来,然后利用前缀和统计前i区间有多少个顶峰,然后就判断sum[l+k-1]-sum[l-1]有多少个顶峰,求最大即可,注意:要把边界上的顶峰删除
第二种方法:尺缩法
首先将左端点l=1,右端点r=l+k-1,然后先暴力,算出这个区间的顶峰
因为区间固定,每次l++,r++,然后判断新成为边界的l是否是上一个区间的顶峰,是就顶峰数减一,且要判断上一个区间的右边界是否为顶峰,是就顶峰数加一
AC代码:
#include<bits/stdc++.h>
using namespace std;
int T,k,n,ans,lans;
int a[200100],sum[200100];
int main() {
scanf("%d",&T);
while(T--) {
ans=0,lans=1;
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
int l=1,r=l+k-1,tmp=0;
for(int i=l; i<=r; i++) //先暴力统计第一个区间的顶峰数
if(i!=l&&i!=r&&a[i]>a[i-1]&&a[i]>a[i+1]) tmp++;
if(tmp>ans) ans=tmp,lans=l;
while(r<=n-1) {
l++,r++;
if(a[l]>a[l-1]&&a[l]>a[l+1]) tmp--;//判断成为边界的左端点是否是顶峰
if(a[r-1]>a[r-2]&&a[r-1]>a[r]) tmp++;//判断上一个区间的右端点是否是顶峰
if(tmp>ans) ans=tmp,lans=l;
}
printf("%d %d\n",ans+1,lans);//别忘了加一
}
}
C. Nastya and Strange Generator
题目大意:
一大长串英文实在是看累了,其实题目就是让你判断一个序列是否能够满足如下规律:
例如:6 7 4 5 1 2 3
1能够到最后这个序列的最后一位都是连续的,然后把这段删除
删除后序列:6 7 4 5
4能够到最后这个序列的最后一位都是连续的,然后把这段删除
删除后序列:6 7
6能够到最后这个序列的最后一位都是连续的,然后把这段删除
删除后序列:无
如果能够一直按照以上规律到最后删除序列为空为止,就输出YES,否则输出NO
解题思路:
没啥好说的,把删除这一麻烦的操作,改成标记即可
AC代码:
#include<bits/stdc++.h>
using namespace std;
int T,n;
int p[100100],pos[100100],vis[100100];
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%d",&p[i]);
pos[p[i]]=i;//pos[]记录每个数在p[]中的位置
}
int num=1,f=1,loc=pos[num];//从1开始,f代表这个序列是否可行
vis[loc]=vis[n+1]=1;//初始化为1
while(num<=n&&f) {
// cout<<"loc="<<loc<<" num="<<num<<" vis[loc]="<<vis[loc]<<endl;
loc++;//位置加加
if(vis[loc]) loc=pos[++num],vis[loc]=1;//如果当前位置被访问过
//意味着被删除(vis[n+1]=1也是这个道理)
else {//如果未被访问过
if(p[loc]==num+1) num++,vis[loc]=1;//如果是符合连续的,则继续操作
else f=0;//如果不连续,则把标记置为0
}
}
if(f) printf("YES\n");
else printf("NO\n");
for(int i=1; i<=n+1; i++) vis[i]=pos[i]=p[i]=0;//重新赋值,因为有多组数据
}
}