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;
}