DP之收了前几天的flag系列【树状数组优化
来源:互联网 发布:mac如何转换输入法 编辑:程序博客网 时间:2024/06/07 00:16
确切地说……
并不算是收了自己的flag吧……
因为我前两天都在打模拟赛……
所以可以叫做“没有收flag”(强行不收flag)
好的这次来扯一道题叫做:
不是那么显然的数据结构优化dp系列之树状数组。
先来看一道题:
题意:求最长不上升子序列。
f[i] = max{j < i && seq[j] >= seq[i]|f[j]} + 1;
于是,我们有了:
O(n^2)做法。
对于最长上升子序列,我们可以维护一个数组叫做S,它保存的是:
S[i] : 在所有长度为i上升子序列中,结尾的最小值。
例如这个东西:1 2 3 4 5:S[3] = 3。
我们发现,for all i < j ,S[i] < S[j],理由是我们可以很无赖地从一个子序列里找……比如长度为3的肯定由长度为2的转移过来,所以我们可以知道长度为2的尾部肯定比长度为3的尾部小……
知道这个之后,我们知道S[]是一个递增的序列,那么可以这样来想:
我们每次找seq[i]所能取到的最大的f[i],也就意味着在S[]里使得max{S[j] < seq[i]|j}、、、也就是说、、、我们可以二分查找seq[i]在S数组里对应了哪一个合法的位置、、、因为S是递增的、、、
那么对于一个不上升的序列,我们怎么办呢?
我们发现,其实只需要把seq的值改成负数并且略微修改一下二分查找的过程即可,代码后面贴、、、
问题来了:
请问树状数组在什么地方得到了体现呢?(一脸萌萌哒的表情)
这个和树状数组并没有任何关系……只不过我想起来顺带说一下……这个是二分优化,虽然不知道它非常广泛的应用是什么……
以上是我的胡言乱语、、、
下面正式开始进入树状数组的优化话题。
我们注意到,f[i] = max{i > j && seq[i] <= seq[j]|f[j]} + 1;
这个东西吧,它可以这样想:
我们每次都询问在1~seq[i]区间内的最大的f[i]。
机智的小朋友们反应了过来:没错!线段树!
很好,seq[i] <= 1e+9 || seq[i] 为小数。
小朋友们又反应了过来:离散化!
很好,线段树常数太大了,而且不太好写。
小朋友们:(一脸幽怨)树状数组!
先说树状数组的询问操作:
询问1~seq[i]的最大值,好搞。 for(int i = san[seq[i]]; i > 0; i -= i & - i)
;
san[]表示已经离散化过了。『是不是感觉很方便』
修改:
从s到n的数组都要改。
for(int i = s; i <= n ; i += i & - i);
代码如下:
1.二分优化:
#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <iostream>#define Rep(i,n) for(int i = 1; i <= n ; i ++)#define N 100005#define CLR(a,b) memset(a,b,sizeof(a))int seq[N],S[N];using namespace std;int BinSearch(int l,int r,int p){ while(l <= r){ int mid = l + r >> 1; if(S[mid] <= p)l = mid + 1; else if(S[mid] > p)r = mid - 1; } return l;}int main (){ int n; while(~scanf("%d",&n)){ int ans = 0; Rep(i,n) scanf("%d",&seq[i]),seq[i] = - seq[i]; CLR(S,127); Rep(i,n){ int j = BinSearch(1,n,seq[i]); // printf("**%d %d**\n",j,seq[i]); S[j] = seq[i]; ans = max(ans,j); } printf("%d\n",ans); } return 0;}
2.线段树优化:
有写线段树那个时间树状数组早就敲完了……
3.树状数组优化:
#include<algorithm>#include<cmath>#include<cstdio>#include<cstring>#define Rep(i,n) for(int i = 1; i <= n ; i ++)#define RepG(i,x) for(int i = head[x] ;~ i ; i = edge[i].next)#define Rep_d(i,n) for(int i = n ; i > 0 ; i --)#define Rep_0(i,n) for(int i = 0 ; i < n ; i ++)#define RD(i,x,n) for(int i = x; i <= n ; i ++)#define T_Q(i,n) for(int i = n; i > 0; i -= i & (- i))#define T_U(i,x,n) for(int i = x; i <= n ; i += i & (- i))#define CLR(a,b) memset(a,b,sizeof(a))#define v edge[i].tousing namespace std;int read(){ char ch = getchar(); while(ch < '0' || ch > '9')ch = getchar (); int x = 0; while(ch >= '0' && ch <= '9')x = 10 * x + ch - '0',ch = getchar (); return x;}int n;int f[100005],seq[100005],san[100005],t[100005];bool cmp(int a,int b){return a > b;}int Query(int x){ int ans = 0; T_Q(i,x)ans = max(t[i],ans); return ans;}void Upd(int Up,int s){ T_U(i,s,n) t[i] = max(t[i],Up);}int Bin_search(int s){ int l = 1,r = n; while(l < r){ int mid = l + r >> 1; if(san[mid] > s)l = mid + 1; else if(san[mid] < s)r = mid - 1; else return mid; } return l;}int main(){ n = read(); Rep(i,n) seq[i] = read(),san[i] = seq[i]; sort(san + 1,san + 1 + n,cmp); Rep(i,n) seq[i] = Bin_search(seq[i]); Rep(i,n){ f[i] = Query(seq[i]) + 1; Upd(f[i],seq[i]); } printf("%d\n",Query(n)); return 0;}
来看我今天做的一个Codeforces水题,这个是我写的线段树优化……
相!当!丑!
题意:
简 单 的 DP, 题意大概这样:
按照顺序给你n块圆柱蛋糕的半径和高,蛋糕都可以放在桌子上,其中小的可以放在大的上面,求最大的蛋糕。 (n<= 100000;r,h <= 50000)
数学模型:求所有不下降序列的元素中,和最大的那个序列的和。
f[i]表示强制选i作(托盘)最后一个蛋糕时的最大体积。
有f[i] = max{j < i && V[i] > V[j]|f[j]} + V[i];
也就是每次都要询问:
1~V[i]区间内的最大值!
树状数组优化即可,然而……算了不说了看代码吧。
/* http://codeforces.com/contest/629/problem/D ID:SingleLyra PROG:Codeforces629D LANG:C++ Solution: 简 单 的 DP, 题意大概这样: 按照顺序给你n块圆柱蛋糕,蛋糕都可以放在桌子上,其中小的可以放在大的上面,求最大的蛋糕。 (n<= 100000;r,h <= 50000) 数学模型:求所有不下降序列的元素中,和最大的那个序列的和。 (然后就被何神秒杀了=,=) 有dp方程: f[i]表示强制选择第i个蛋糕所能形成的当前最大蛋糕。 f[i] = max{j < i && V[j] > V[i] |f[j]} + V[i]; 然后发现了复杂度为n^2,根本过不去…… 然后发现它就是长着一张"我要优化"的脸…… "何神,这道题用什么dp优化啊?" "离散化之后树状数组。" 于是我默默地打了个线段树…… 2333333…… 注意一点…… 这里的离散化是一种非常高贵的离散化,可以以后来用…… */ /* Rep(i,n)seq[i].X = 1ll * R[i] * R[i] * H[i],seq[i].Y = - i;// 把下标所代表的序号设为负数,所以对于a[i] == a[j](i < j)排序后一定在j之后。 sort(seq + 1 ,seq + 1 + n); Rep(i,n){ int id = -seq[i].Y; //为什么可以不按照原来顺序的原因:当a[i] > a[j] 时,a[i]必然出现在a[j]之后,所以如果某个数a[i]出现在a[j]之前,那么我们肯定,f[j]不会由f[i]转移得到、、、也就是说,我们询问的是、、、在id之前出现的&&小于seq[id]的最大值、、、 f[id] = Query(1,1,n,1,id) + seq[i].X ; Upd(1,1,n,id,f[id]); } */#include<algorithm>#include<cmath>#include<cstdio>#include<cstring>#define Rep(i,n) for(int i = 1; i <= n ; i ++)#define RepG(i,x) for(int i = head[x] ;~ i ; i = edge[i].next)#define Rep_d(i,n) for(int i = n ; i > 0 ; i --)#define Rep_0(i,n) for(int i = 0 ; i < n ; i ++)#define RD(i,x,n) for(int i = x; i <= n ; i ++)#define CLR(a,b) memset(a,b,sizeof(a))#define X first#define Y second#define v edge[i].to#define pii pairtypedef long double ld;typedef long long ll;using namespace std;int read(){ char ch = getchar(); while(ch < '0' || ch > '9')ch = getchar (); int x = 0; while(ch >= '0' && ch <= '9')x = 10 * x + ch - '0',ch = getchar (); return x;}const ld pi = M_PI;int R[100005],H[100005];ll f[100005];ll t[100005 << 2];pii <ll,int>seq[100005];void Upd(int x,int l,int r,int s,ld U){ if(l == r){ t[x] = U; return; } int mid = l + r >> 1; if(mid >= s)Upd(x << 1,l,mid,s,U); else Upd(x << 1 | 1,mid + 1,r,s,U); t[x] = max(t[x << 1],t[x << 1 | 1]);}ll Query(int x,int l,int r,int Ql,int Qr){ if(l > Qr || r < Ql)return 0; if(l >= Ql && r <= Qr)return t[x]; int mid = l + r >> 1; long long ans = 0; if(mid >= Ql)ans = max(Query(x << 1,l,mid,Ql,Qr),ans); if(mid < Qr)ans = max(Query(x << 1 | 1 ,mid + 1,r,Ql,Qr),ans); return ans;}int main(){ int n = read(); Rep(i,n) R[i] = read(),H[i] = read(); Rep(i,n)seq[i].X = 1ll * R[i] * R[i] * H[i],seq[i].Y = - i; sort(seq + 1 ,seq + 1 + n); ll ans = 0; Rep(i,n){ int id = -seq[i].Y; f[id] = Query(1,1,n,1,id) + seq[i].X ; Upd(1,1,n,id,f[id]); } ld ans_ = (ld)Query(1,1,n,1,n) * pi; printf("%.9f\n",(double) ans_); return 0;}
- DP之收了前几天的flag系列【树状数组优化
- 【HDU4991】dp 树状数组优化
- hdu5542 树状数组优化dp
- BZOJ3594 树状数组优化DP
- 3594: [Scoi2014]方伯伯的玉米田 DP+树状数组优化
- [bzoj3594][Scoi2014]方伯伯的玉米田 树状数组优化dp
- bzoj3594 方伯伯的玉米田 树状数组优化dp
- [BZOJ2131]免费的馅饼-树状数组优化DP
- hdu4455之树状数组+DP
- HDU - 4991(树状数组优化 dp)
- hdu 3450 树状数组优化dp
- bzoj4361 isn(树状数组优化DP)
- [dp+树状数组优化] CF597C. Subsequences
- hdu 5542(树状数组优化dp)
- hdu 3450(树状数组优化dp)
- hdu 2227(树状数组优化dp)
- hdu 4991(树状数组优化dp)
- Codeforce 597C(dp+树状数组优化)
- 26. Remove Duplicates from Sorted Array
- (一) Freemarker 简介 && 环境搭建
- 查询1/2/3/4
- C++中的new/delete与operator new/operator delete
- C语言itoa()函数和atoi()函数详解(整数转字符C实现)
- DP之收了前几天的flag系列【树状数组优化
- C# 观察者模式.
- InnoDB: Unable to find the AUTOINC column
- c++ vector用法
- 先序建二叉树,中序遍历
- (二)Freemarker 基本数据类型
- GMM高斯混合模型
- 2015年总结下
- 今夕,何夕