题意:给你一串序列,让你序列中找出 类似这样的 1 2 3 4 5 4 3 2 1 的最大长度的子串,子串特性:1长度可以写成2*n+1,其中前n+1的序列是严格上升的,后n+1个是严格递减的;
一开始我的思路是这样的:第一遍先dp一遍,找出所有的递增序列,并且记录上升序列最后一个元素的位置,第二遍 从这些上升序列的最后一个元素的位置开始寻找,若能找到一个长度与上升相等的 下降序列就停止可以输出了,而且要从最长的开始找,这个想法 个人认为是没有什么问题的,但是写起来比较难处理,很难表达,后来又重新换了个思路:
先顺着dp一遍,再逆着dp一遍,都dp上升序列,第二遍dp的是它的逆序,而且对于符合性质的子串 他们的 dp1[i] == dp2[n - i + 1],这个稍微推一下就知道了,这样就比较好处理了,直接正反一次 nlong方法即可,但是原先的版子有问题,后来换了个版子过了,
#include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #include<string> #include<queue> #include<stack> #include<map> #include<vector> #include<cmath> #include<memory.h> #include<set> //#define ll long long #define ll __int64 #define eps 1e-7 #define inf 0xfffffff //const ll INF = 1ll<<61; using namespace std; //vector<pair<int,int> > G; //typedef pair<int,int > P; //vector<pair<int,int> > ::iterator iter; // //map<ll,int >mp; //map<ll,int >::iterator p; //#define IN freopen("c:\\Users\\linzuojun\\desktop\\input.txt", "r", stdin) //#define OUT freopen("c:\\Users\\linzuojun\\desktop\\output.txt", "w", stdout) int dp1[100000 + 5]; int num[10000 + 5]; int dp2[100000 + 5]; int tmp[10000 + 5]; int n; void clear() { memset(dp1,0,sizeof(dp1)); memset(num,0,sizeof(num)); memset(dp2,0,sizeof(dp2)); memset(tmp,0,sizeof(tmp)); } void LIS(int *dp,int *a) { // nlogn的LIS,n^2会超时的 int Stack[10000 + 5]; Stack[0] = -1; int top = 0; for(int i=1;i<=n;i++) { int left = 1; int right = top; int pos = -1; while(left <= right) { int mid = (left + right)/2; if(Stack[mid] < a[i]) left = mid + 1; else right = mid - 1; } Stack[left] = a[i]; dp[i] = 1; if(a[i] > Stack[top]) { Stack[++top] = a[i]; dp[i] = top; } } } int main() { while(scanf("%d",&n) == 1 ) { clear(); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); tmp[n - i + 1] = num[i];//tmp相当于num的倒序 } LIS(dp1,num); LIS(dp2,tmp); int ans = -1,temp = 0; for(int i=1;i<=n;i++) { temp = min(dp1[i],dp2[n - i + 1]) * 2 - 1;//记得找小的那个 ans = max(temp,ans); } printf("%d\n",ans); } return EXIT_SUCCESS; }
原文:http://blog.csdn.net/yitiaodacaidog/article/details/19170745