P8816 [CSP-J 2022] 上升点列
PanShanxing · · 题解
0.前言
当初在考场上花了不到十分钟基本想出正解,又花了不到二十分钟把代码敲完了,然而因为自己思维方式太离谱所以最终只拿了85pts。
如今找LLZ要回了自己的考场代码,稍作修改,于是A了。
不得不说的是自己的思路确实不够完善,因此也并没有可惜这15分的意思(反正1=也拿到了),倒是长了个教训。
如今把我写这道题的全过程分享在自己的blog里,也算是总结了。
那我们就开始吧。
1.在考场上
拿到这题以后一眼最长上升子序列,看了一眼数据范围觉得很水,于是想了个简单的思路。
只是最长上升子序列的做法而已,给点排一下序然后直接dp即可。
实在是不知道如何仔细讲解这个思路,主要是真要细讲的话可能也就说说最长上升子序列这种东西,实在是没什么必要。
但是我在面对“最后不一定把所有点加完,所以还需要把没加的点加上”时,脑子抽了一下:我选择了先比较dp数组中的最大答案,最后再找这些最大值中能加的最多的点数量。
但是事实上,在某些情况下,dp数组中的某个非最大值在加上没加的点之后就是最优解,而我恰好忽略了这一点。
我真是个弱智。
顺便把考场代码贴一下吧。
#include<bits/stdc++.h>
using namespace std;
int n,k,dp[501][101],ans=0,orz=1000;
struct dots{
int x,y;
bool operator < (const dots &zgc)const{
if (x!=zgc.x){
return x<zgc.x;
}
return y<zgc.y;
}
}a[501];
int main()
{
freopen("point.in","r",stdin);
freopen("point.out","w",stdout);
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
dp[i][0]=1;
}
sort(a+1,a+1+n);
for (int i=2;i<=n;i++){
for (int j=1;j<i;j++){
if (a[i].x<a[j].x||a[i].y<a[j].y){
continue;
}
int kk=a[i].x-a[j].x+a[i].y-a[j].y-1;
for (int add=kk;add<=k;add++){
dp[i][add]=max(dp[i][add],dp[j][add-kk]+1+kk);
}
}
}
for (int i=1;i<=n;i++){
for (int j=0;j<=k;j++){
ans=max(ans,dp[i][j]);
}
}
for (int i=1;i<=n;i++){
for (int j=0;j<=k;j++){
if (ans==dp[i][j]){
orz=min(orz,j);
}
}
}
printf("%d",ans+k-orz);
return 0;
}
2.呼之欲出的正解
只需要修改一下考场代码即可。
将最后的找最大值的部分改了一下,改成直接找答案。
于是AC。
#include<bits/stdc++.h>
using namespace std;
int n,k,dp[501][101],ans=0;
struct dots{
int x,y;
bool operator < (const dots &zgc)const{
if (x!=zgc.x){
return x<zgc.x;
}
return y<zgc.y;
}
}a[501];
int main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
dp[i][0]=1;
}
sort(a+1,a+1+n);
for (int i=2;i<=n;i++){
for (int j=1;j<i;j++){
if (a[i].x<a[j].x||a[i].y<a[j].y){
continue;
}
int kk=a[i].x-a[j].x+a[i].y-a[j].y-1;
for (int add=kk;add<=k;add++){
dp[i][add]=max(dp[i][add],dp[j][add-kk]+1+kk);
}
}
}
for (int i=1;i<=n;i++){
for (int j=0;j<=k;j++){
ans=max(ans,dp[i][j]+k-j);
}
}
printf("%d",ans);
return 0;
}
撒花,顺便再次感叹我是弱智。