UVA12983 The Battle of Chibi 树状数组+DP

先容蒟蒻吐槽一波:模数看错调了一两小时。。。

题意:

要你在一个长度为n的序列中找到长度为m的严格上升子序列的个数,然后答案对1e9+7取模。

举个例子:

5 3

1 3 4 2 5

那么符合条件的序列就有: 1 3 4 ,1 2 5, 1 3 5 ,1 4 5, 3 4 5, 答案就是5。

既然和上升子序列有关,那么就是DP了。

注意我这里设的i,j有点不一样,表示的是

前j个数,以a[j]结尾的,严格上升子序列长度为i的方案数。(反过来也OK,只不过待会BIT就得开两维)

容易得到状态转移方程:f[i][j]=sigma (f[i-1][k]), 0<=k<j 且 a[k]<a[j]。

那么的话n3的暴力是很容易打的。

但是如果只是n3题目就没多大意义了。

我们考虑优化:

显然对于一个j我们只关心他前面的满足 a[k]<a[j] 的所有的方案数的和。

那么这就可以直接建立一个权值树状数组,(注意到ai<=1e9 离散化即可)

对于每一个数先查询之前的比他小的,统计一下答案。

再把自己的值插入自己的对应的位置就可以了。

可以发现由于我们的 i  是在外层循环,即已经限制了长度, 所以内部更新时i-1不变。

所以只要直接建一维的BIT就好了,不要考虑把长度也记下来,只是每次i++后,清空BIT。

#include <bits/stdc++.h>
using namespace std;
inline int gi () {
    int x=0,w=0; char ch=0;
    while (!(ch>=‘0‘ && ch<=‘9‘)) {if (ch==‘-‘) w=1; ch=getchar ();}
    while (ch>=‘0‘ && ch<=‘9‘) x= (x<<3)+(x<<1)+(ch^48), ch=getchar ();
    return w?-x:x;
}

#define LL long long
#define INF 0x3f3f3f3f;
#define RGI register int
#define lowbit(x) x&-x

const int N=1010;
const int Mod=1e9+7;

LL Ans,BIT[N],f[N][N];
int T,n,m,tot,a[N],b[N];

inline void New_Case () {
    memset (f, 0 ,sizeof (f));
    f[0][0]=1, Ans=0, a[0]=1;
}

inline void Modify (int x, int val) {
    for (;x<=n;x+=lowbit(x)) BIT[x]=(BIT[x]+val%Mod)%Mod;
}

inline LL Query (int x) {
    LL sum=0;
    for (;x;x-=lowbit(x)) sum=(sum+BIT[x])%Mod;
    return sum;
}

int main ()
{
    T=gi ();
    for (RGI id=1;id<=T;++id) {
        RGI i,j;
        New_Case ();
        n=gi (), m=gi ();
        for (i=1;i<=n;++i) a[i]=b[i]=gi ();
        sort (b+1, b+n+1);
        for (i=1;i<=n;++i) a[i]=lower_bound (b+1, b+n+1, a[i])-b+1;
        for (i=1;i<=m;++i) {
            memset (BIT, 0, sizeof (BIT));
            Modify (a[0], f[i-1][0]);
            for (j=1;j<=n;++j) {
                f[i][j]=Query (a[j]-1);
                Modify (a[j], f[i-1][j]%Mod);
            }
        }
        for (i=1;i<=n;++i) Ans= (Ans+f[m][i])%Mod;
        printf ("Case #%d: %lld\n", id, Ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Bhllx/p/9822815.html

时间: 2024-11-08 13:56:51

UVA12983 The Battle of Chibi 树状数组+DP的相关文章

hdu 3030 Increasing Speed Limits (离散化+树状数组+DP思想)

Increasing Speed Limits Time Limit: 2000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 481    Accepted Submission(s): 245 Problem Description You were driving along a highway when you got caught by the road p

hdu4455之树状数组+DP

Substrings Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1571    Accepted Submission(s): 459 Problem Description XXX has an array of length n. XXX wants to know that, for a given w, what is

【树状数组+dp】HDU 5542 The Battle of Chibi

http://acm.hdu.edu.cn/showproblem.php?pid=5542 [题意] 给定长为n的序列,问有多少个长为m的严格上升子序列? [思路] dp[i][j]表示以a[i]结尾的长度为j的严格上升子序列有多少个 dp[i][j]=sum{dp[k][j-1]},k小于i且a[k]<a[i] 区间dp,复杂度为O(n^3) 会超时,第三层循环求和用树状数组加速 时间复杂度为O(n^2logn) 离散化的时候排序后不去重(否则WA) [Accepted] #include<

Codeforces 597C. Subsequences (树状数组+dp)

题目链接:http://codeforces.com/contest/597/problem/C 给你n和数(1~n各不同),问你长为k+1的上升自序列有多少. dp[i][j] 表示末尾数字为i 长度为j的上升子序列个数,但是dp数组是在树状数组的update函数中进行更新. update(i, val, j)函数表示在i的位置加上val,更新dp[i][j]. sum(i, j)就是求出末尾数字小于等于i 且长度为j的子序列有多少个. 1 //#pragma comment(linker,

【树状数组+dp+离散化】Counting Sequences

https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/G [题意] 给定一个数组a,问这个数组有多少个子序列,满足子序列中任意两个相邻数的差(绝对值)都不大于d. [思路] 首先,朴素的dp思想: dp[i]为以a[i]结尾的子问题的答案,则dp[i]=sum(dp[k]),k<i&&|a[k]-a[i]|<=d 但是时间复杂度为O(n^2),会超时. 我们可以这样想: 如果数组a排好序后,dp[i]就是区间(a[

hdu5125 树状数组+dp

hdu5125 他说的是n个人每个人都有两个气球a,b,气球各自都有相应的体积,现在让他们按照序号排列好来,对他们的a气球体积值计算最长上升子序列,对于这整个排列来说有m次机会让你将a气球替换成b气球(允许不使用完),问最后的最长上升子序列 的长度是多少,哈哈,当然用dp的思想我们很容易就能知道状态的转移 dp[1000][1000][2],但是苦于状态转移的复杂度太大了达到了 n*n*m肯定受不了,那好我们可以列出这个方程的转移方法 (0表示a气球1为b气球) dp[i][j][0]=max(

POJ 3378 Crazy Thairs(树状数组+DP)

[题目链接] http://poj.org/problem?id=3378 [题目大意] 给出一个序列,求序列中长度等于5的LIS数量. [题解] 我们发现对于每个数长度为k的LIS有dp[k][i][a[i]]=dp[k-1][i-1][0~a[i]-1] 我们用5个树状数组维护不同长度的LIS,递推即可,注意答案超过LL,需要用大数. [代码] #include <cstdio> #include <algorithm> #include <cstring> usi

hdu 2227 树状数组+dp

题意是求一个数列的不递减的子序列的个数: 很显然,如果只用dp来做的话时间是O(n*n) 因为dp[i]为前i个数可能的方案,则状态转移方程为dp[i]=sum(dp[j],j<i&&num[j]<=num[i])+1 对小数据坑定能过 但大数据就超时了,这里用到了树状数组来优化: 先对num按数来进行排序,(这道题因为数据较大  用到了离散化) 因为更新是是按原序更新的,及i之前的num[j]一定比num[i]小,维护了不递减的原则,更新是从mark[i](表示原序列i在排序

BZOJ-1264 :[AHOI2006]基因匹配Match(树状数组+DP)

1264: [AHOI2006]基因匹配Match Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 904  Solved: 578[Submit][Status][Discuss] Description 基因匹配(match) 卡卡昨天晚上做梦梦见他和可可来到了另外一个星球,这个星球上生物的DNA序列由无数种碱基排列而成(地球上只有4种),而更奇怪的是,组成DNA序列的每一种碱基在该序列中正好出现5次!这样如果一个DNA序列有N种不同的碱基构成