scu oj 4441 Necklace(dp+树状数组求上升序列最大和)
2016-08-28 13:45
267 查看
题意:N个数构成一个环,现在可以删除一些数,使得这个环可以分成连续的三部分:
X部分:所有数不降
Y部分:仅含一个值为10000的数
Z部分:所有数不增
(X,Y中不含值为10000的数),值为10000的数不超过10个。
求满足条件的环中,剩余数字的和最大为多少?
题解:枚举值为10000的数。确定值为10000的数的位置后,环就断成了一条链。我们可以用动态规划求出(1,i)的数的不增序列的最大和,同理求出(i,n)的不增序列的最大和。然后枚举断点即可。在动态规划的过程中需要用到树状数组优化转移。
因为要求是先不增后不降,所以树状数组维护时需要从10000-a【i】更新。我换了一种写法,就是树状数组向前更新,向后查找,也过了
X部分:所有数不降
Y部分:仅含一个值为10000的数
Z部分:所有数不增
(X,Y中不含值为10000的数),值为10000的数不超过10个。
求满足条件的环中,剩余数字的和最大为多少?
题解:枚举值为10000的数。确定值为10000的数的位置后,环就断成了一条链。我们可以用动态规划求出(1,i)的数的不增序列的最大和,同理求出(i,n)的不增序列的最大和。然后枚举断点即可。在动态规划的过程中需要用到树状数组优化转移。
因为要求是先不增后不降,所以树状数组维护时需要从10000-a【i】更新。我换了一种写法,就是树状数组向前更新,向后查找,也过了
#include <cstdio> #include <iostream> #include <cstring> #include <string> #include <cstdlib> #include <algorithm> #include <cmath> #include <vector> #include <set> #include <list> #include <queue> #include <map> using namespace std; #define L(i) i<<1 #define R(i) i<<1|1 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-3 #define maxn 100010 #define MOD 1000000007 #define inf 0x3f3f3f3f3f3f3f3f int n,m; int c[maxn]; int a[maxn<<1]; int dp1[maxn],dp2[maxn]; int sum1[maxn],sum2[maxn]; void update(int x,int tmp) { while(x) { c[x] = max(c[x],tmp); x -= x & (-x); } } int get_max(int x) { int ret = 0; while(x < 10000) { ret = max(ret,c[x]); x += x & (-x); } return ret; } int solve(int pos) { memset(c,0,sizeof(c)); memset(dp1,0,sizeof(dp1)); memset(sum1,0,sizeof(sum1)); if(a[pos+1] == 10000) dp1[1] = 0; else { dp1[1] = a[pos+1]; update(a[pos+1],dp1[1]); } sum1[1] = dp1[1]; for(int i = pos+2; i < pos+n; i++) { if(a[i] == 10000 || !a[i]) continue; dp1[i-pos] = get_max(a[i]) + a[i]; update(a[i],dp1[i-pos]); sum1[i-pos] = max(sum1[i-pos-1],dp1[i-pos]); } memset(c,0,sizeof(c)); memset(dp2,0,sizeof(dp2)); memset(sum2,0,sizeof(sum2)); if(a[pos+n-1] == 10000) dp2[n-1] = 0; else { dp2[n-1] = a[pos+n-1]; update(a[pos+n-1],dp2[n-1]); } sum2[n-1] = dp2[n-1]; for(int i = pos+n-2; i > pos; i--) { if(a[i] == 10000 || !a[i]) continue; dp2[i-pos] = get_max(a[i]) + a[i]; update(a[i],dp2[i-pos]); sum2[i-pos] = max(sum2[i-pos+1],dp2[i-pos]); } int ans = 0; // for(int i = 1; i < n; i++) // printf("%d %d\n",sum1[i],sum2[i]); for(int i = 1; i < n-1; i++) ans = max(ans,sum1[i]+sum2[i+1]); return ans+10000; } int main() { int t; //scanf("%d",&t); while(scanf("%d",&n) != EOF) { for(int i = 0; i < n; i++) scanf("%d",&a[i]); for(int i = n; i < 2 * n; i++) a[i] = a[i-n]; int ans = 0; for(int i = 0; i < n; i++) if(a[i] == 10000) ans = max(ans,solve(i)); printf("%d\n",ans); } }
#include <cstdio> #include <iostream> #include <cstring> #include <string> #include <cstdlib> #include <algorithm> #include <cmath> #include <vector> #include <set> #include <list> #include <queue> #include <map> using namespace std; #define L(i) i<<1 #define R(i) i<<1|1 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-3 #define maxn 100010 #define MOD 1000000007 #define inf 0x3f3f3f3f3f3f3f3f int n,m; int c[maxn]; int a[maxn<<1]; int dp1[maxn],dp2[maxn]; int sum1[maxn],sum2[maxn]; void update(int x,int tmp) { while(x <= 10000) { c[x] = max(c[x],tmp); x += x & (-x); } } int get_max(int x) { int ret = 0; while(x) { ret = max(ret,c[x]); x -= x & (-x); } return ret; } int solve(int pos) { memset(c,0,sizeof(c)); memset(dp1,0,sizeof(dp1)); memset(sum1,0,sizeof(sum1)); if(a[pos+1] == 10000) dp1[1] = 0; else { dp1[1] = a[pos+1]; update(10000-a[pos+1],dp1[1]); } sum1[1] = dp1[1]; for(int i = pos+2; i < pos+n; i++) { if(a[i] == 10000) continue; dp1[i-pos] = get_max(10000-a[i]) + a[i]; update(10000-a[i],dp1[i-pos]); sum1[i-pos] = max(sum1[i-pos-1],dp1[i-pos]); } memset(c,0,sizeof(c)); memset(dp2,0,sizeof(dp2)); memset(sum2,0,sizeof(sum2)); if(a[pos+n-1] == 10000) dp2[n-1] = 0; else { dp2[n-1] = a[pos+n-1]; update(10000-a[pos+n-1],dp2[n-1]); } sum2[n-1] = dp2[n-1]; for(int i = pos+n-2; i > pos; i--) { if(a[i] == 10000) continue; dp2[i-pos] = get_max(10000-a[i]) + a[i]; update(10000-a[i],dp2[i-pos]); sum2[i-pos] = max(sum2[i-pos+1],dp2[i-pos]); } int ans = 0; // for(int i = 1; i < n; i++) // printf("%d %d\n",sum1[i],sum2[i]); for(int i = 1; i < n-1; i++) ans = max(ans,sum1[i]+sum2[i+1]); return ans+10000; } int main() { int t; //scanf("%d",&t); while(scanf("%d",&n) != EOF) { for(int i = 0; i < n; i++) scanf("%d",&a[i]); for(int i = n; i < 2 * n; i++) a[i] = a[i-n]; int ans = 0; for(int i = 0; i < n; i++) if(a[i] == 10000) ans = max(ans,solve(i)); printf("%d\n",ans); } }
相关文章推荐
- scu oj 4441 Necklace(dp+树状数组)
- hdu 1087最大上升子序列的和
- 经典字符串算法 “最长上升子序列,最大连续子序列和,最长公共子串”
- uva10605 最大公共子序列转化为最大上升子序列
- 动态规划-3003-序列的最大上升子序列
- dp专题 第十三题 最大上升子序列的和
- 最大上升子序列的和
- ZOJ 1108 FatMouse's Speed【DP】【最大上升子序列】
- HDU-1087 Super Jumping! Jumping! Jumping! (线性dp 上升子序列最大和)
- 最大上升子序列(从前往后) nlogn 和最大上升序列(从后往前)
- hdoj 1950 Bridging signals【二分求最大上升子序列长度】【LIS】
- HDOJ --1950 Bridging signal【利用二分法来求最大上升子序列长度】
- hdoj 1069 Monkey and Banana(上升子序列最大和)
- 九度 1480:最大上升子序列和(动态规划思想求最值)
- hdoj1087Super Jumping! Jumping! Jumping!(上升序列求最大和)
- [dp](不连续)最大公共上升子序列 POJ 2127
- 动态规划例题 最大上升自序列
- 最大连续子序列和,最大上升子序列和,最长上升子序列,最长公共子串,最长公共子序列,最长上升公共子序列
- 3532:最大上升子序列和(最长上升子序列变式)
- scu oj 4441 Necklace(dp+树状数组)(*)