[JZOJ 5600] Arg

题意:求最少LIS覆盖...
思路:
计算\(LIS\)时我们一般用\(dp\)表示到当先位置时以当前位置结尾的\(LIS\)最长长度。
那么这个数组保证单调不降,我们考虑二进制表示。
然后就是转移了...
不过蜜汁\(RE\)啊,自测能过...

#include <bits/stdc++.h>
using namespace std;
inline int read(){
    int q=0,f=1;char ch = getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;ch=getchar();
    }
    while(isdigit(ch)){
        q = q * 10 + ch - '0';
        ch = getchar();
    }
    return q*f;
}
int n;
int ans;
int f[20010000];
int c[20];int m;
int wtf[20];
int a[20];
int c2[20];
inline void dfs(int x,int lim,int k) {
    if(x > n) {
        if(!lim) ans += f[k];
        return;
    }
    k += c[x - 1];
    dfs(x + 1,lim,k);
    k += c[x - 1];
    dfs(x + 1,lim - 1,k);
}


int main () {
    freopen("Arg.in","r",stdin);
    freopen("Arg.out","w",stdout);
    scanf("%d %d",&n,&m);
    for(int i = 1;i <= m; ++i) {
        scanf("%d",&a[i]);
    }
    c[0] = c2[0] = 1;
    for(int i = 1;i <= n; ++i) {
        c[i] = c[i - 1] * 3;
        c2[i] = c2[i - 1] * 2;
    }
    f[0] = 1;
    for(int i = 0;i <= c2[n] - 2; ++i) {
        bool ok = 1;
        bool tag = 1;
        for(int j = 1;j <= m; ++j) {
            if((i & c2[a[j] - 1]) == 0) {
                ok = 0;
            }
            else if(!ok) {
                tag = 0;
                break;
            }
        }
        if(tag) {
            for(int ii = i;1;ii = (ii - 1) & i) {
                int v = 0;
                for(int j = 1;j <= n; ++j) {
                    if(ii & c2[j - 1]) v += c[j - 1];
                    if(i & c2[j - 1]) v += c[j - 1];
                }
                if(f[v]) {
                    for(int j = 1;j <= n; ++j) {
                        if(v / c[j - 1] % 3 == 0) {
                            int V = v + 2 * c[j - 1];
                            for(int k = j + 1;k <= n; ++k) {
                                if(V / c[k - 1] % 3 == 2) {
                                    V -= c[k - 1];
                                    break;
                                }
                            }
                            f[V] += f[v];
                        }
                    }
                }
                if(ii == 0) break;
            }
        }
    }
    dfs(1,m,0);
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/akoasm/p/9584909.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值