URAL1523(dp+树状数组)
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=41224#problem/B
分析:可以设dp[i][j]表示以i结尾长度为j的子序列的个数,那么更新就是dp[i][j]=∑dp[k][j-1],其中k<i,而且a[k]>a[i]。而要更新dp值,可以用树状数组维护,按顺序插入序列值,那么树状数组的值就可以表示比它小的长度为j-1的所有子序列的和,这样就可以在logn的时间更新dp值了,所以总复杂度是O(n*k*logn)
树状数组有两种用途(以一维树状数组举例):
1.单点更新,区间查询(即求和)
单点更新时,是往树根(即c[n])拓展
而区间查询时,是往叶子节点(即c[1])拓展
2.区间更新,单点查询
区间更新时,是往叶子节点(即c[1])拓展
单点查询时,往树根(即c[n])拓展
这两个操作只不过是在update()和sum()方法中的+和-替换一下而已。
下面解释一下“区间更新时,是往叶子节点(即c[1])拓展” 和 “单点查询时,往树根(即c[n])拓展” 的原因
举例说明吧:
c[1]=a[1];
c[2]=a[1]+a[2];
c[3]=a[3];
c[4]=a[1]+a[2]+a[3]+a[4];
c[5]=a[5];
c[6]=a[5]+a[6];
c[7]=a[7];
c[8]=a[1]+...+a[8];
假如我要更新区间[3,7],那么我首先更新[1,7],即该区间+1;再更新[1,2],该区间-1:
由于更新时往叶子节点拓展的,所以更新[1,7]时:c[7]++,c[6]++,c[4]++。
可以发现,这三个正好包含了a[1]~a[7]一次,相当于a[1]~a[7]都更新一遍 而更新[1,2]时:c[2]--,包含了a[1],a[2]。
那么当我查询某一值a[i],由于是往根节点拓展,所以每个包含a[i]的c[j]都会遇到一次(更新时每个a[i]变化一次),
即之前凡是更新过的值我都会加上。
如我想查询a[2],那么a[2]=c[2]+c[4]+c[8]=-1+1+0=0;
查询a[3],那么a[3]=c[3]+c[4]+c[8]=0+1+0=1。
1)树状数组区间更新,单点求值方法
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #define LL long long
- #define M 1000000000
- #define maxn 22222
- #define lson l,m,rt<<1
- #define rson m+1,r,rt<<1|1
- using namespace std;
- int a[maxn],c[maxn];
- int dp[maxn][];//dp[i][j]表示以a[i]为结尾长度为j的子序列;dp[i][j]=∑dp[k][j-1]且a[i]>a[k]
- int n,k;
- int lowbit(int x)
- {
- return x&(-x);
- }
- int sum(int i)
- {
- LL res=;
- while(i<=n)
- {
- res=(res+c[i])%M;
- i+=lowbit(i);
- }
- return res;
- }
- void update(int i,int x)
- {
- while(i)
- {
- c[i]=(c[i]+x)%M;
- i-=lowbit(i);
- }
- }
- int main()
- {
- while(scanf("%d%d",&n,&k)>)
- {
- memset(dp,,sizeof(dp));
- for(int i=;i<=n;i++)
- {
- scanf("%d",&a[i]);
- dp[a[i]][]=;
- }
- for(int i=;i<=k;i++)
- {
- memset(c,,sizeof(c));
- for(int j=i-;j<=n;j++)
- {
- dp[a[j]][i]=sum(a[j]);//求长度为i以a[j]点为结束的逆序对数值
- update(a[j],dp[a[j]][i-]);//更新处在0~a[j]的数逆序对+dp[a[j]][i-1]
- }
- }
- LL ans=;
- for(int i=;i<=n;i++)
- {
- ans=(ans+dp[a[i]][k])%M;
- }
- printf("%lld\n",ans);
- }
- }
2)树状数组单点更新,区间求值方法
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #define LL long long
- #define M 1000000000
- #define maxn 22222
- #define lson l,m,rt<<1
- #define rson m+1,r,rt<<1|1
- using namespace std;
- int a[maxn],c[maxn];
- int dp[maxn][];//dp[i][j]表示以a[i]为结尾长度为j的子序列;dp[i][j]=∑dp[k][j-1]且a[i]>a[k]
- int n,k;
- int lowbit(int x)
- {
- return x&(-x);
- }
- void update(int x,int y)
- {
- while(x<=n)
- {
- c[x]=(c[x]+y)%M;
- x+=lowbit(x);
- }
- }
- int sum(int x)
- {
- int res=;
- while(x)
- {
- res=(res+c[x])%M;
- x-=lowbit(x);
- }
- return res;
- }
- int main()
- {
- while(scanf("%d%d",&n,&k)>)
- {
- for(int i=;i<=n;i++)
- {
- scanf("%d",&a[i]);
- dp[i][]=;
- }
- int res;
- for(int i=,j=n;i<j;i++,j--) res=a[i],a[i]=a[j],a[j]=res;
- for(int i=;i<=k;i++)
- {
- memset(c,,sizeof(c));
- for(int j=i-;j<=n;j++)
- {
- dp[a[j]][i]=sum(a[j]);//求在0~a[j]比a[j]小的所在点逆序对之和
- update(a[j],dp[a[j]][i-]);//更新a[j]点的逆序对
- }
- }
- int ans=;
- for(int i=;i<=n;i++) ans=(ans+dp[a[i]][k])%M;
- printf("%d\n",ans);
- }
- return ;
- }
URAL1523(dp+树状数组)的更多相关文章
- 树形DP+树状数组 HDU 5877 Weak Pair
//树形DP+树状数组 HDU 5877 Weak Pair // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 // 这道题要离散化 #i ...
- bzoj 1264 [AHOI2006]基因匹配Match(DP+树状数组)
1264: [AHOI2006]基因匹配Match Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 793 Solved: 503[Submit][S ...
- 【bzoj2274】[Usaco2011 Feb]Generic Cow Protests dp+树状数组
题目描述 Farmer John's N (1 <= N <= 100,000) cows are lined up in a row andnumbered 1..N. The cows ...
- 奶牛抗议 DP 树状数组
奶牛抗议 DP 树状数组 USACO的题太猛了 容易想到\(DP\),设\(f[i]\)表示为在第\(i\)位时方案数,转移方程: \[ f[i]=\sum f[j]\;(j< i,sum[i] ...
- codeforces 597C C. Subsequences(dp+树状数组)
题目链接: C. Subsequences time limit per test 1 second memory limit per test 256 megabytes input standar ...
- HDU 2227 Find the nondecreasing subsequences (DP+树状数组+离散化)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2227 Find the nondecreasing subsequences ...
- ccpc_南阳 C The Battle of chibi dp + 树状数组
题意:给你一个n个数的序列,要求从中找出含m个数的严格递增子序列,求能找出多少种不同的方案 dp[i][j]表示以第i个数结尾,形成的严格递增子序列长度为j的方案数 那么最终的答案应该就是sigma( ...
- HDU 2838 (DP+树状数组维护带权排序)
Reference: http://blog.csdn.net/me4546/article/details/6333225 题目链接: http://acm.hdu.edu.cn/showprobl ...
- [poj3378] Crazy Thairs (DP + 树状数组维护 + 高精度)
树状数组维护DP + 高精度 Description These days, Sempr is crazed on one problem named Crazy Thair. Given N (1 ...
随机推荐
- chrome你这是入侵OSX了么?
今天突然发现安装chrome的应用后,会在Dock中出现如下图标,点击即可启动chrome相关应用,很是方便.
- Head First PHP &MySQL学习笔记
近期一段时间在学习PHP,买了<Head First PHP&MySQL>中文版这本书,之前买过<Head First设计模式>,感觉这系列的书籍整体来说非常不错. ...
- strip 命令的使用方法
用途 通过除去绑定程序和符号调试程序使用的信息,降低扩展公共对象文件格式(XCOFF)的对象文件的大小. 语法 strip [ -V ] [ -r [ -l ] | -x [ -l ] | -t | ...
- Swift - 使用atlas图集实现动画效果(SpriteKit游戏开发)
我们通常继承SKSpriteNode来实现游戏中的元素,除了可以使用图片作为纹理皮肤外.我们还可以使用动画纹理集来实现动画播放. 动画纹理集的制作也很简单,首先要有一套动画序列图,然后把它们放到一个文 ...
- smartforms初始化
smartforms 第一次打开的页面是和prd环境下的一样,需要跑一个程序才能编辑
- Servlet过滤器——过滤器分析流量
1.概述 Servlet过滤器可以对用户提交的数据或服务器返回的数据进行更改.任何到达服务器的请求都会首先经过过滤器的处理.本实例应用过滤器的这个特点,编写了一个在过滤器中统计网站流量的实例. 本实例 ...
- [eclipse] 三个操作技巧
[eclipse] 三个操作技巧 1.快捷键Ctrl+Shift+i:Debug调试中直接获取方法的返回值 在下图代码中,想知道getHost(),则在调试时运行完该句代码后,选中"urlU ...
- python 循环中的else
众多语言中都有if else这对条件选择组合,但是在python中还有更多else使用的地方,比如说循环for,或者while都可以和else组合. 下面简单介绍一下for-else while-el ...
- 硬盘重装Ubuntu12.04的感受
好久没更blog了,最近这两天系统也出了问题,win7蓝屏,ubuntu进不去-.后来win7整好了,ubuntu依旧顽固.用惯了linux,就不想在转到win7下面了,估计是习惯了各种敲命令的感觉吧 ...
- oracle 在操作blob该字段是否会产生很多redo
操作blob该字段是否会产生很多redo,答案是否定的.以下来做一个实验,測试数据库版本号是11.2.0.1.0: --创建一张表做測试之用 create table test_blob ( id ...