DP【洛谷P1704】 寻找最优美做题曲线

【洛谷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”(不加引号,全是小写字母)。

自己YY的做法A了两道题了,十分开心,不过看到了我的做法居然和这道题的作者的作法一样,不太开心。。。

这道题就是在一个序列中让你选定一些数,再在必选这些数的基础上找出LIS。

我的做法挺鬼畜的。

首先对于一个要选定的点,我们可以排除一些绝对不会选的点。条件就是在当前点前面的点的值如果大于当前点,那么因为当前点必选,所以就可以排除那个前面的点,同样的,如果当前点后面的点的值小于当前点的值,那么我们也不选。

这样,我们就可以得到一个新的数组,在这个数组里直接求一遍LIS就行了。

刚刚自己想了一下,忽然感觉这个做法是错误的,因为我感觉在新数组里选LIS并没有保证原本要选的点一定被选。

但是并不是这样的,(机房一堆大佬反驳我。。。可是我说我的做法错他们反驳说对是什么鬼啊。。。)

我们可以这么想,对于一个一定要选的点,经过我们的处理,在这个点之前是一段全部小于他的数,后面是一段全部大于他的数,那么不管我们在这前后两段怎么选,都一定不会有一个数去替代他的位置,也就是说,我们可以用反证法证不选他不是最优的就可以了。

开心。

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int wx=500017;
inline int read(){
	int sum=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
	return sum*f;
}
int n,m,ans[wx],len,tot;
int flag[wx],a[wx],b[wx],f[wx],vis[wx];
int main(){
	n=read();m=read();
	for(int i=1,x;i<=m;i++)x=read(),flag[x]=1;
	for(int i=1;i<=n;i++)a[i]=read();
	int last=0;
	for(int i=1;i<=n;i++){
		if(a[i]>a[last])vis[i]=1;
		if(flag[i])last=i;
	}
	last=n+1;a[n+1]=0x3f3f3f3f;
	for(int i=n;i>=1;i--){
		if(a[i]>a[last]&&flag[i]){
			printf("impossible");return 0;
		}
		if(a[i]>a[last])vis[i]=0;
		if(flag[i])last=i;
	}
	for(int i=1;i<=n;i++){
		if(vis[i])b[++tot]=a[i];
	}
	ans[1]=b[1];len=1;
	for(int i=2;i<=tot;i++){
		if(b[i]>ans[len]){
			ans[++len]=b[i];
		}
		else{
			int pos=lower_bound(ans,ans+len,b[i])-ans;
			ans[pos]=b[i];
		}
	}
	printf("%d
",len);
	return 0;
}
原文地址:https://www.cnblogs.com/wangxiaodai/p/9774427.html