[SCU4441] Necklace [2015 Sichuan Province Contest Final F]
2016-07-26 19:52
375 查看
题意
N个数构成一个环,现在可以删除一些数,使得这个环可以分成连续的三部分:X部分:所有数不降;Y部分:仅含一个值为10000的数;Z部分:所有数不增。(X,Y中不含值为10000的数),值为10000的数不超过10个。求满足条件的环中,剩余数字的和最大值。题解
枚举值为10000的数。确定值为10000的数的位置后,将环变为以这个10000为两端的一条链。枚举断点i,我们可以用动态规划求出(1,i)的数的不增序列的最大和,同理求出(i,n)的不增序列的最大和。发现每个权值不超过10000,可以在动态规划的过程中用树状数组优化转移。代码
/****************************************\ * Author : ztx * Title : F - Necklace * ALG : dp + BIT * CMT : * Time : \****************************************/ #include <cstdio> #define Rep(i,l,r) for(i=(l);i<=(r);i++) #define rep(i,l,r) for(i=(l);i< (r);i++) #define Rev(i,r,l) for(i=(r);i>=(l);i--) #define rev(i,r,l) for(i=(r);i> (l);i--) typedef long long ll ; typedef double lf ; int CH , NEG ; template <typename TP>inline void read(TP& ret) { ret = NEG = 0 ; while (CH=getchar() , CH<'!') ; if (CH == '-') NEG = true , CH = getchar() ; while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ; if (NEG) ret = -ret ; } template <typename TP>inline void readc(TP& ret) { while (ret=getchar() , ret<'!') ; while (CH=getchar() , CH>'!') ; } template <typename TP>inline void reads(TP *ret) { ret[0]=0;while (CH=getchar() , CH<'!') ; while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ; ret[ret[0]+1]=0; } #include <cstring> #define maxn 100010LL #define max(a,b) (a)>(b)?(a):(b) #define lb (p&(-p)) int n , ans ; int a[maxn<<1] , c[20010] , f[maxn<<1] , right[maxn<<1] , left[maxn<<1] ; inline int GetMax(int p) { int ret=0 ; for (;p;p-=lb) ret=max(ret,c[p]) ; return ret ; } inline void Insert(int p,int w) { for (;p<20001;p+=lb) c[p]=max(c[p],w) ; } int main() { int i , j ; // #define READ #ifdef READ freopen("data.in" ,"r",stdin ) ; freopen("me.out","w",stdout) ; #endif while (scanf("%d", &n) != EOF) { ans = 0LL ; Rep (i,1,n) read(a[i]) , a[i+n] = a[i] ; Rep (i,1,n) if (a[i] == 10000) { memset(right,0,sizeof right) ; memset(c,0,sizeof c) ; memset(f,0,sizeof f) ; rep (j,i,i+n) { if (a[j] != 10000) f[j] = GetMax(20001-a[j])+a[j] , Insert(20001-a[j],f[j]) ; right[j] = max(right[j-1],f[j]) ; } memset(left,0,sizeof left) ; memset(c,0,sizeof c) ; memset(f,0,sizeof f) ; rev (j,i+n,i) { if (a[j] != 10000) f[j] = GetMax(20001-a[j])+a[j] , Insert(20001-a[j],f[j]) ; left[j] = max(left[j+1],f[j]) ; } rep (j,i,i+n) ans = max(ans,right[j]+left[j+1]+10000) ; } printf("%d\n", ans) ; } #ifdef READ fclose(stdin) ; fclose(stdout) ; #else getchar() ; getchar() ; #endif return 0 ; }
相关文章推荐
- AIX系统的环境变量设置
- 剑指offer面试题39:二叉树深度以及判断平衡二叉树
- js实例
- C语言sscanf() 用法举例
- 【Emit】关于System.MethodAccessException解决方案
- Aix下如何运行Java程序
- Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_The49DayPersonalFullscreenGiftModel", referenced from: objc-class-ref in The49DayPersonalRoomGiftModel.o ld: symbol(s) not found for a
- 【Ural1028】Stars-线段树和树状数组入门题
- 【杭电】[4907]Task schedule
- csapp - lab1
- hdu5762 Teacher Bo (暴力)
- HDOJ-4004 The Frog's Games
- HDOJ 1551 Cable master
- CentOS下php.ini配置文件详解
- 本地通知
- java泛型
- Java 打印空心菱形
- 使用Spinner控件实现选项选择
- js中精确的乘除运算
- 替换元素和非替换元素的学习