[HDU 5568] sequence2 dp+大数

http://acm.hdu.edu.cn/showproblem.php?pid=5568

题意:给定长度为 n 的序列 bi​​,求有多少长度为 k 的但是本质不同的上升子序列。本质不同的意思就是两个子序列中至少有一个位置的下标不同。

思路:dp, dp[i][j] 表示已经选了 i 个数做子序列前驱是 j 。 dp[i][j] = sum( dp[i + 1][l]) ( l > j, ary[l] > ary[j])。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

struct BigInteger  //大数类
{
    int len;
    int arg[105];
    BigInteger(int x = 0){
        IntToBigInteger(x);
    }
    void IntToBigInteger(int x)
    {
        len = 0;
        memset(arg, 0, sizeof(arg));
        do{
            arg[len++] = x % 10;
            x = x / 10;
        }while (x);
    }
    friend ostream& operator<<(ostream &out, BigInteger w)
    {
        for (int i = w.len - 1; i >= 0; i--){
            out<<w.arg[i];
        }
        return out;
    }
    friend BigInteger operator+(BigInteger r, BigInteger w)
    {
        int len = r.len > w.len ? r.len : w.len;
        for (int i = 0; i < len; i++){
            if(i < w.len)
                r.arg[i] = r.arg[i] + w.arg[i];
            r.arg[i + 1] += r.arg[i] / 10;
            r.arg[i] = r.arg[i] % 10;
        }
        while (r.arg[len] >= 10){
            r.arg[len + 1] += r.arg[len] / 10;
            r.arg[len] = r.arg[len] % 10;
            len++;
        }
        if(r.arg[len]) len++;
        r.len  = len > r.len ? len : r.len;
        return r;
    }
};

int n, m;
int ary[105];

BigInteger dp[105][105];



BigInteger Dfs(int deep, int pos, int pre)  //deep, 选了多少个做子序列,pos, 搜索到那个下标,pre 前驱
{
    if(deep == m - 1)
        return 1;
    if(pos == n)
        return 0;
    if(dp[deep][pre].len != -1)
        return dp[deep][pre];
    BigInteger res = 0;
    for(int i = pos + 1; i < n; i++){
        if(ary[pre] < ary[i])
            res = res + Dfs(deep + 1, i, i);
    }
    dp[deep][pre] = res;
    return dp[deep][pre];
}

int main()
{
    while(~scanf("%d%d", &n, &m)){
        for(int i = 0; i < n; i++){
            scanf("%d", &ary[i]);
        }
        BigInteger res = 0;
        for(int i = 0; i < 105; i++){
            for(int k = 0; k < 105; k++){
                dp[i][k].len = -1;
            }
        }
        for(int i = 0; i < n; i++){
            res = res + Dfs(0, i, i);
        }
        cout<<res<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

achonor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值