博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷 P1020 导弹拦截(LIS)
阅读量:5025 次
发布时间:2019-06-12

本文共 3496 字,大约阅读时间需要 11 分钟。

 

 

参考资料:

  [1]:

  [2]:

 

相关概念解释:

  1.串 & 子序列

    一个串的子串是指该串的一个连续的局部。

    如果不要求连续,则可称为它的子序列。

    比如对串: "abcdefg" 而言,"ab","abd","bdef" 等都是它的子序列。  

    特别地,一个串本身,以及空串也是它的子序列。

  2.最长上升子序列 & 最长不下降子序列

    最长上升子序列(Longest Increasing Subsequence,LIS),在计算机科学上是指一个序列中最长的单调递增的子序列。

    而最长不下降子序列则不一定要保证单调递增,只要保证  a[ i ] <= a[ j ] ( j > i , 且在序列范围内)即可。

现在开始回归主题:

题意:

  中文题意,不再赘述;

题解:

  第一问求最长不上升子序列的长度;

  第二问求这个序列里面最少有多少最长不上升子序列。

  难点就在与第二问,如何求呢?

  看大佬博客说“求一个序列里面最少有多少最长不上升序列等于求这个序列里最长上升序列的长度”,我也不懂为啥 /小纠结,或许,这就是大佬吧。

废话少说,上AC代码:

1 #include
2 using namespace std; 3 #define INF 0x3f3f3f3f 4 const int maxn=1e5+50; 5 6 int n; 7 int a[maxn]; 8 int dp[maxn]; 9 10 void Solve()11 {12 int len=0;13 dp[len]=INF;14 for(int i=1;i <= n;++i)15 {16 if(a[i] <= dp[len])17 dp[++len]=a[i];18 else19 {20 int l=0,r=len+1;21 while(r-l > 1)//二分出最后一个不小于 a[i] 的下标22 {23 int mid=(l+r)/2;24 if(dp[mid] >= a[i])//注意,此处取到"=="判给了 l25 l=mid;26 else27 r=mid;28 }29 dp[r]=a[i];30 }31 }32 printf("%d\n",len);33 len=0;34 dp[len]=-1;35 for(int i=1;i <= n;++i)//求最长上升子序列36 {37 if(a[i] > dp[len])38 dp[++len]=a[i];39 else40 {41 int t=lower_bound(dp+1,dp+len+1,a[i])-dp;42 dp[t]=a[i];43 }44 }45 printf("%d\n",len);46 }47 48 int main()49 {50 while(~scanf("%d",&a[++n]))//以回车结束输入的输入方式51 continue;52 n--;53 Solve();54 }
View Code

bug:

  (1):输入方式

  正确的输入方式:

1 while(~scanf("%d",&a[++n]))//以回车结束输入的输入方式2     continue;3 n--;//最后一个 n 接受的是 '\n' ,所以需要减去
View Code

  错误的输入方式,返回 RE,至今不知道为啥,有知道的大佬可否告知一二%%%%%%%%

1 do2 {3     scanf("%d",&a[++n]);4 }while(getchar() != '\n');
View Code

  第一种输入方式在本地无法测试,但 OJ 可以。

  第二种输入方式,虽然本地可以测试,但提交后返回 RE,应该是输入停不下来的吧。

 


分割线:2019.6.3

对第二问有了深一步的理解;

第二问求得是最少需要多少导弹拦截系统,根据贪心的思想,每个导弹系统都希望可以拦截尽可能多的导弹;

那么第一个导弹拦截系统最多可以拦截 cnt1 个,cnt1 = 最长不上升子序列的长度;

第二个导弹拦截系统最多可拦截 cnt2 个,cnt2 = 去掉第一次拦截的导弹后的最长不上升子序列的长度;

.............

第x个导弹拦截系统最多可拦截 cntx 个,cntx = 去掉前(x-1)次拦截的导弹后的最长不上升子序列长度;

假设第一次拦截的最低的导弹高度为 a1

第二次拦截的最低的导弹高度为 a2;

..............

第x次拦截的最低导弹高度为 ax

那么,a1 < a2 < ... < ax

用反证法证明:

  假设 ai > aj ( i<j );

  那么,在第 i 次拦截中结尾的不应该是 ai,而应该是比 ai 还小的 aj

  但已经假设 ai 是第 i 次拦截中的最低导弹高度,与假设矛盾;

所以,第二问求的是最长上升子序列;

AC代码:

1 #include
2 using namespace std; 3 #define INF 0x3f3f3f3f 4 const int maxn=1e5+50; 5 6 int n; 7 int a[maxn]; 8 int tmp[maxn]; 9 int d[maxn];10 11 void Solve()12 {13 int k=n;14 for(int i=1;i <= n;++i)15 tmp[i]=a[k--];16 17 int cnt=0;18 d[cnt]=-1;19 for(int i=1;i <= n;++i)20 {21 if(tmp[i] >= d[cnt])22 d[++cnt]=tmp[i];23 else24 {25 int t=upper_bound(d+1,d+cnt+1,tmp[i])-d;26 d[t]=tmp[i];27 }28 }29 printf("%d",cnt);30 31 cnt=0;32 for(int i=1;i <= n;++i)33 {34 if(a[i] > d[cnt])35 d[++cnt]=a[i];36 else37 {38 int t=lower_bound(d+1,d+cnt+1,a[i])-d;39 d[t]=a[i];40 }41 }42 printf(" %d\n",cnt);43 44 return ;45 }46 int main()47 {48 // freopen("C:/Users/14685/Desktop/stdin&&stdout/contest","r",stdin);49 n=0;50 while(~scanf("%d",&a[++n]));51 n--;52 Solve();53 54 return 0;55 }
View Code

 

转载于:https://www.cnblogs.com/violet-acmer/p/9852550.html

你可能感兴趣的文章
线程池总结
查看>>
Learning to rank (software, datasets)
查看>>
git常见问题
查看>>
.NETFramework:template
查看>>
HM16.0之帧内模式——xCheckRDCostIntra()函数
查看>>
Jmeter性能测试 入门
查看>>
安卓动画有哪几种?他们的区别?
查看>>
Nodejs学习总结 -Express入门(一)
查看>>
web前端优化
查看>>
ssh 连接原理及ssh-keygen
查看>>
vs2013编译qt程序后中文出现乱码
查看>>
【转】IOS数据库操作SQLite3使用详解
查看>>
Android官方技术文档翻译——ApplicationId 与 PackageName
查看>>
设计网站大全
查看>>
JVM CUP占用率过高排除方法,windows环境
查看>>
【转】JAVA字符串格式化-String.format()的使用
查看>>
【转】ButterKnife基本使用--不错
查看>>
【转】VS2012编译出来的程序,在XP上运行,出现“.exe 不是有效的 win32 应用程序” “not a valid win32 application”...
查看>>
函数中关于const关键字使用的注意事项
查看>>
微信架构(转)
查看>>