hdu 4996 1~n排列LIS值为k个数

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

直接贴bc题解

按数字1-N的顺序依次枚举添加的数字,用2N的状态保存在那个min数组中的数字,每次新添加数字可以根据位置计算出新的min数组。
怎么快速计算呢?这里如果枚举N的位置是不可行的,这样2n的state记录的信息不够。很巧妙的思路是枚举放在当前位置的数字,比如说1-N-1的排列状态下,枚举第N位为K,那么1-N-1位的>=k的数字全加1,就得到了一个1-N的排列。
当然这个算法是有问题的,但是由于求的是长度,所以所有j代表的状态并不能正确表示对应的上升序列,因为每个有值的dp[j]必然有j&1 == 1,但是却奇迹般的AC了..所以大致理解算法思想和AC原因但是这个算法的解释略有疑问...
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr0(x) memset(x,0,sizeof(x))
typedef long long LL;
const int maxn = 1<<20;
int n,k;
LL f[20][20],dp[maxn],tmp[maxn];

int cal(int x)
{
    int ans = 0;
    for(int i = 0;i < 20;++i)
        if((1<<i)&x)
            ans++;
    return ans;
}
void init () {
    dp[1] = f[1][1] = 1;
    for(int i = 1;i < 18;++i){
        for(int j = 0;j < (1<<i);++j)
            tmp[j] = dp[j];
        for(int j = 0;j < (1<<(i+1));++j)
            dp[j] = 0;
        for(int j = 0;j < (1<<i);++j)if(tmp[j]){
            for(int k = 0;k <= i;++k){
                int tot = 0,c[20],st = 0;
                for(int l = 0;l < i;++l){
                    if((1<<l) & j){
                        c[tot] = l;
                        if(c[tot] >= k)
                            c[tot]++;
                        tot++;
                    }
                }
                c[tot++] = k;
                for(int l = 0;l < tot;++l){
                    if(c[l] > k){
                        c[l] = k;
                        break;
                    }
                }
                for(int l = 0;l < tot;++l){
                    st |= (1<<c[l]);
                }
                dp[st] += tmp[j];
            }
        }
        for(int j = 0;j < (1<<(i+1));++j)
            f[i+1][cal(j)] += dp[j];
    }
}
int main() {
    init();
    int _;RD(_);while(_--){
        RD2(n,k);
        printf("%I64d
",f[n][k]);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/zibaohun/p/4046798.html