luogu P1704 寻找最优美做题曲线

题目背景

nodgd是一个喜欢写程序的同学,前不久(好像还是有点久了)洛谷OJ横空出世,nodgd同学当然第一时间来到洛谷OJ刷题。于是发生了一系列有趣的事情,他就打算用这些事情来出题恶心大家……

题目描述


洛谷OJ刷题有个有趣的评测功能,就是系统自动绘制出用户的“做题曲线”。所谓做题曲线就是一条曲线,或者说是折线,是这样定义的:假设某用户在第b[i]天AC了c[i]道题,并且b[i]严格递增,那么该用户的做题曲线就是平面上点(i,c[i])依次连出的一条折线。比如你在第1天做了3道题,第3天做了4道题,第6天做了1道题,那么你在前6天的做题曲线就是从点(1,3)到点(2,4)到点(3,1)的连续折线。
nodgd同学可以预测出自己未来N天每条能够AC题目的数量,同时有一个很无趣的爱好,就是单调递增,nodgd强迫自己的做题曲线保持严格的单调递增。但是出于某些原因,nodgd在某些日子(共有K天)必须刷题,而且刷题数量一定是预计的数量(体现nodgd的神预测)。nodgd同学想知道,在这样的情况下,自己最多有多少天可以刷题,不过nodgd同学还有大量的数学竞赛题、物理竞赛题、英语竞赛题、美术竞赛题、体育竞赛题……要做,就拜托你来帮他算算了。

输入输出格式
输入格式:
第一行两个正整数,N和K,表示nodgd预测了未来N天每天做题的数量,其中K天必须刷题。

第二行K个正整数p[i],表示第p[i]天必须刷题(1<=p[i]<=N,保证每个p[i]不同)。

第三行N个正整数c[i],表示在第i天nodgd可以AC的题目数量必须是c[i]。

输出格式:
一行。

如果能找到严格递增的做题曲线:一个正整数,表示nodgd最多有多少天可以刷题。

如果找不到严格递增的做题曲线:直接输出“impossible”(不加引号,全是小写字母)。

输入输出样例

输入样例#1:

13 4
2 13 8 7
6 10 9 8 9 10 11 16 14 12 13 14 18 

输出样例#1:

5

说明

数据范围

1<=N<=500000,1<=K<=N/2
1<=p[i]<=N,保证每个p[i]不同,不保证p[i]按大小顺序输入
1<=c[i]<=10^9

若果一数在序列内严格比他前面的书大,比后面的数小,那么这个数一定存在于最长上升子序列中
显然在规定必须选取的连续两天内,比前一天小的和比后一天大的一定不合法,去掉之后便可使规定选取数变为上述数
删掉不合法数然后求一遍最长上升子序列就好,注意,第七组数据规定了必须要取第0天,这是一个坑点,当然是O(nlogn)的啦~(≧▽≦)/~

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 500007;
int a[maxn],b[maxn],tmp[maxn],len=1,n,m;
bool tag[maxn];
bool check() {
	sort(b+1,b+m+1);
	for(int i=2;i<=m;++i) {
		if(a[b[i]]<a[b[i-1]]) {
			puts("impossible");return 1;
		}
	}
	return 0;
}
int mid_serch(int x) {
	int l=1,r=len;
	while(l<=r) {
		int mid=(l+r)>>1;
		if(tmp[mid]<a[x])l=mid+1;
		else r=mid-1;
	}
	return l;
}
int main () {
	int t=0;
	//freopen ("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) {scanf("%d",b+i);if(b[i]==0)t=1;}
	for(int i=1;i<=n;++i) scanf("%d",a+i);
	if(check())return 0;
	for(int i=2;i<=m;i++) 
		for(int j=b[i-1]+1;j<b[i];++j) 
			if(a[j]<=a[b[i-1]]||a[j]>=a[b[i]])tag[j]=1;
	for(int i=1;i<b[1];++i)
        if(a[i]>=a[b[1]])
            tag[i]=true;
	for(int i=b[m]+1;i<=n;++i)
        if(a[i]<=a[b[m]])
            tag[i]=true;
	tmp[1]=a[1];
	for(int i=2;i<=n;++i) {
		if(tag[i])continue;
		if(a[i]>tmp[len])tmp[++len]=a[i];
		else {
			int pos=mid_serch(i);
			tmp[pos]=a[i];
		}
	}
	//for(int i=1;i<=len;i++) {
	//	printf("%d
",tmp[i]);
	//}
	printf("%d
",len+t);
	return 0;
}
原文地址:https://www.cnblogs.com/sssy/p/7741767.html