HDU 4521 小明系列问题——小明序列 DP – LIS加强版 #by Plato
http://acm.hdu.edu.cn/showproblem.php?pid=4521
题意:给个序列,求其最长上升序列(LIS)。增加了个额外的条件,子序列中相邻两个距离必须大于D。
Idea: 数据比较大,N = 10^5,得用 NlogN的算法,并且考虑那个额外的条件。
大致的,增加一个辅助数组,minv[j]代表[距离i距离大于D的]长度为j的子序列的 最小的尾巴。详细的懒写了。
#include <cstdio> #include <iostream> #include <fstream> #include <cstring> #include <string> #define OP(s) cout<<#s<<"="<<s<<" "; #define TP(i,j,k) cout<<#i<<"="<<i<<" "<<#j<<"="<<j<<" "<<#k<<"="<<k<<endl; #define PP(s) cout<<#s<<"="<<s<<endl; using namespace std; const int INF = 1<<29; int minv[100010]; int bsearch(int low,int high,int target) { while (low < high) { int mid = (low + high + 1)>>1; if (minv[mid] < target) low = mid; else high = mid - 1; } return high; } int main() { freopen("test.txt","r",stdin); int N,D; while (~scanf("%d%d",&N,&D)) { static int a[100010]; for (int i = 1;i <= N;i++) scanf("%d",a+i); static int f[100010]; memset(f,0,sizeof(f)); for (int i = 0;i < 100010;i++) minv[i] = INF; for (int i =1 ;i <= N;i++) { int k = bsearch(0,N,a[i]); f[i] = k+1; int j = i-D; if (j > 0) { int len = f[j]; minv[len] = min(a[j],minv[len]); } } int ans = 0; for (int i = 1;i <= N;i++) if (f[i] > ans) ans = f[i]; cout<<ans<<endl; } return 0; }
{
题外话:说下做那场马拉松的感受吧。
之前注册了马甲去看看了第一天的题目,后面几天的看了部分,周日是主场了。
7:05,到宿舍吧,开机。。。
A题,水。
E题,水。
D题,B题。
B题就是个加强的LIS,觉得可以做,去搜了下NlogN的算法,发现还要处理距离条件,考虑了会,最后还是没写。
看D题过了不少,开始去考虑了。分类讨论:M大于N的,只要切一下就好了;M小于N的话,至少要切(M-N)下。但是要高精度,于是去网上搜了个高精的模版,贴过了~~~
B题觉得写不了,就看C题了。看完就觉得是个较水的最短路,数据小,不用什么优化。不过处理输入的字符串稍有点恶心。
处理读入,Dijstra,然后自信地去提交。当时HDU交的人暴多,一直在排队。就没在意了,去逛了下,回来查代码发现有几处明显的代码错误,修改在提交。不过一直到结束,我第一个交的都在排队。
最后呢。。。华丽的WA了。再看题目,"如果在起点坐的是卧铺,则后面乘坐的车必须全是卧铺"k = 0,k = 1分别建图,补题了。还是WA了。再看题目“k=0表示该车只有硬座,k=1表示该车有卧铺也有硬座”,OK了。
}