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 ...
随机推荐
- Android原生APP内分享
Android原生APP内分享,可实现数据分享以及assets文件夹分享及私有文件分享 项目地址:https://github.com/json-pu/AndroidAppShare.git
- OCP-1Z0-051-题目解析-第31题
31. Evaluate the following SQL commands: SQL>CREATE SEQUENCE ord_seq INCREMENT BY 10 START WITH 1 ...
- gcc中__attribute__ ((constructor(101)))做成.a库成功链接
1.cpp:------------------------------------------------ #include int test() __attribute__ ((construct ...
- MFC 总体理解
在MFC程序中,我们并不经常直接调用Windows API,而是从MFC类创建对象并调用属于这些对象的成员函数.也就是说MFC封装了Windows API 你说你喜欢C++而MFC换一种说法就是一个用 ...
- Android菜鸟的成长笔记(6)——剖析源码学自定义主题Theme
原文:Android菜鸟的成长笔记(6)--剖析源码学自定义主题Theme 还记得在Android菜鸟的成长笔记(3)中我们曾经遇到了一个问题吗?"这个界面和真真的QQ界面还有点不同的就是上 ...
- jsp中将后台传递过来的json格式的list数据绑定到下拉菜单select
<span style="white-space:pre"> </span> <select><c:forEach var="f ...
- JSTL解析——004——core标签库03
上面章节主要讲解<c:forEach>标签,下面讲解其它标签 1.<c:forTokens>标签 forTokens标签与forEach标签类似,独有begin.end.ste ...
- Tokyo Tyrant(TTServer)系列(四)-tcrmgr远程管理与调试
Tokyo Tyrant(TTServer)系列-tcrmgr(远程管理与调试) tcrmgr是TokyoTyrant的管理工具,对ttserver进行管理与执行命令: 通过输入tcrmgr回车,能够 ...
- css js 优化工具
我知道国内很多网页制作人员都还在制作table式网页,这样的网页打开速度很慢.如果要想网站打开速度快,就要学会使用DIV+CSS,将图片写进CSS,这样如果网站内容很多的时候,也不会影响网页的浏览.它 ...
- 一个跨平台的 C++ 内存泄漏检测器
2004 年 3 月 01 日 内存泄漏对于C/C++程序员来说也可以算作是个永恒的话题了吧.在Windows下,MFC的一个很有用的功能就是能在程序运行结束时报告是否发生了内存泄漏.在Linux下, ...