zoukankan      html  css  js  c++  java
  • HDU 5542

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5542

    Problem Description
    Cao Cao made up a big army and was going to invade the whole South China. Yu Zhou was worried about it. He thought the only way to beat Cao Cao is to have a spy in Cao Cao's army. But all generals and soldiers of Cao Cao were loyal, it's impossible to convince any of them to betray Cao Cao.

    So there is only one way left for Yu Zhou, send someone to fake surrender Cao Cao. Gai Huang was selected for this important mission. However, Cao Cao was not easy to believe others, so Gai Huang must leak some important information to Cao Cao before surrendering.

    Yu Zhou discussed with Gai Huang and worked out N information to be leaked, in happening order. Each of the information was estimated to has ai value in Cao Cao's opinion.

    Actually, if you leak information with strict increasing value could accelerate making Cao Cao believe you. So Gai Huang decided to leak exact M information with strict increasing value in happening order. In other words, Gai Huang will not change the order of the N information and just select M of them. Find out how many ways Gai Huang could do this.

    Input
    The first line of the input gives the number of test cases, T(1≤100). T test cases follow.

    Each test case begins with two numbers N(1≤N≤10^3) and M(1≤M≤N), indicating the number of information and number of information Gai Huang will select. Then N numbers in a line, the ith number ai(1≤ai≤10^9) indicates the value in Cao Cao's opinion of the ith information in happening order.

    Output
    For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the ways Gai Huang can select the information.

    The result is too large, and you need to output the result mod by 1000000007(109+7).

    Sample Input
    2
    3 2
    1 2 3
    3 2
    3 2 1

    Sample Output
    Case #1: 3
    Case #2: 0

    Hint

    In the first cases, Gai Huang need to leak 2 information out of 3. He could leak any 2 information as all the information value are in increasing order.
    In the second cases, Gai Huang has no choice as selecting any 2 information is not in increasing order.

    题意:

    给出长度为 $N(1 le N le 10^3)$ 的数字序列(每个数字都在 $[1,10^9]$ 范围内)。

    现在要从中挑选出长度为 $M(1 le M le N)$ 的严格单调递增子序列,问有多少种挑选方案。

    题解:

    首先,不难想到应当假设 $dp[i][j]$ 代表以 $a[i]$ 为结尾的且长度为 $j$ 的严格单增子序列的数目,

    那么自然地,状态转移就是 $dp[i][j] = sum dp[k][j-1]$,其中 $k$ 满足 $1 le k < i$ 且 $a[k]<a[i]$。

    不过,题目是不可能这么简单的……这样纯暴力dp的话时间复杂度为 $O(n^3)$,超时。

    考虑进行优化:

    先对 $dp$ 数组进行改造,假设 $dp[a_i][j]$ 代表:在数字序列的 $[1,i]$ 区间内,以数字 $a[i]$ 为结尾的长度为 $j$ 的严格单增子序列的数目,

    这样一来,原来的 $a[i]$ 的范围在 $[1,10^9]$,数组是开不下的。所以,需要对 $a[1 sim n]$ 先进行离散化,使得所有 $a[i]$ 的范围均在 $[1,n]$,这样数组就开的下了。

    自然而然地,状态转移方程就变成了 $dp[a_i][j] = dp[1][j-1] + dp[2][j-1] + cdots + dp[a_i-1][j-1]$。

    然后,既然要优化求前缀和的速度,不妨对 $dp[1 sim n][1]$ 构造一个树状数组,对 $dp[1 sim n][2]$ 构造一个树状数组,$cdots$,对 $dp[1 sim n][m]$ 构造一个树状数组。

    这样一来,我要求 $dp[1][j-1] + dp[2][j-1] + cdots + dp[a_i-1][j-1]$ 这样一个前缀和就可以在 $O(log n)$ 时间内完成。总时间复杂度变为 $O(n^2 log n)$。

    那么最后所求答案即为 $dp[1][m]+dp[2][m]+ cdots + dp[n][m]$。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e3+5;
    const ll mod=1e9+7;
    
    int n,m;
    int a[maxn];
    ll dp[maxn][maxn];
    
    vector<int> v;
    inline int getid(int x) {
        return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
    }
    
    inline int lowbit(int x){return x&(-x);}
    void add(int pos,int len,ll val)
    {
        val%=mod;
        while(pos<=n)
        {
            dp[pos][len]+=val;
            dp[pos][len]%=mod;
            pos+=lowbit(pos);
        }
    }
    ll ask(int pos,int len)
    {
        ll res=0;
        while(pos>0)
        {
            res+=dp[pos][len];
            res%=mod;
            pos-=lowbit(pos);
        }
        return res;
    }
    
    int main()
    {
        int T;
        cin>>T;
        for(int kase=1;kase<=T;kase++)
        {
            scanf("%d%d",&n,&m);
    
            v.clear();
            for(int i=1;i<=n;i++) scanf("%d",&a[i]), v.push_back(a[i]);
            sort(v.begin(),v.end());
            v.erase(unique(v.begin(),v.end()),v.end());
            for(int i=1;i<=n;i++) a[i]=getid(a[i]);
    
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=m;j++)
                {
                    if(j==1) add(a[i],j,1);
                    else
                    {
                        ll tmp=ask(a[i]-1,j-1);
                        add(a[i],j,tmp);
                    }
                }
            }
            printf("Case #%d: %lld
    ",kase,ask(n,m));
        }
    }
  • 相关阅读:
    修改采购订单项目的内容显示、更改
    100小时学会sap傻瓜式入门版财务篇之co篇
    100小时学会sap傻瓜式入门版销售与分销sd篇
    100小时学会sap傻瓜式入门版生产计划pp篇
    ABAP SYNTAX COLLECTION II
    100小时学会sap傻瓜式入门版物料管理mm篇
    【转】systemconfigkickstart Package selection is disabled due to problems
    【转】如何在同一台机器上配置多个jboss应用服务器实例(以jboss4.0.5为标准)
    Windows7 install jeklly
    【转】VBoxManage命令详解
  • 原文地址:https://www.cnblogs.com/dilthey/p/9898230.html
Copyright © 2011-2022 走看看