zoukankan      html  css  js  c++  java
  • 题解 CF327E 【Axis Walking】

    题目链接

    Solution [CF327E] Axis Walking

    题目大意:给定一个数列,求有多少种排列方式使得这个数列的任意前缀和不会成为(k)个数中的任意一个

    动态规划,计数,(lowbit)优化(dp)


    ​分析:看到数据范围(n leq 24)就马上可以意识到这题要么是状压(dp),要么是搜索.可是搜索全排列复杂度高达(24!),而且如果出题人卡你(请意识到这是(CF)的题目),你的剪枝是没有任何软用的.

    ​比如这组数据:

    24
    1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    2
    2333 2333
    

    ​你搜索很不好搞啊,那么我们就只能使用状压(dp)了.既然都上状压(dp)了,状态也就不难定义了吧:

    ​我们用(f[S])来表示选择集合(S)中的数的排列方案总数,最终答案为(f[U]),(U)为全集.

    ​蒟蒻先给出代码,再看具体为何

    #include <cstdio>
    using namespace std;
    const int mod = 1e9 + 7;
    const int maxn = 24;
    long long f[1 << maxn],sum[1 << maxn],val[maxn],no[3],n,k;//f由上文易知,sum[x]表示集合x内元素之和,no就是给定的k个元素,val为原数列
    inline int lowbit(int x){
        return x & (-x);
    }
    int main(){
    #ifdef LOCAL
        freopen("fafa.in","r",stdin);
    #endif
        scanf("%d",&n);
        for(int i = 0;i < n;i++)//读入
            scanf("%d",&val[i]),sum[1 << i] = val[i];//初始化sum数组,很eazy
        scanf("%d",&k);
        for(int i = 0;i < k;i++)
            scanf("%d",&no[i]);
        for(int i = 0;i < n;i++)//dp边界
            f[1 << i] = (val[i] != no[0] && val[i] != no[1]) ? 1 : 0;
        for(int i = 1;i < (1 << n);i++){//进行dp
            sum[i] = sum[i ^ lowbit(i)] + sum[lowbit(i)];
            if(sum[i] == no[0] || sum[i] == no[1])continue;
            for(int j = i;j;j -= lowbit(j)){//枚举集合i的每一个二进制1
                f[i] += f[i ^ lowbit(j)];
                if(f[i] >= mod)f[i] -= mod;//据说可以加速long long取余
            }
        }
        printf("%lld
    ",f[(1 << n) - 1]);//输出
        return 0;
    }
    

    ​先看(sum)数组,(sum[x])表示集合(x)的和,这个很容易理解.因为(i ; xor lowbit(i))(lowbit(i))都是(i)的真子集,所以计算集合(i)时它们都算过了

    ​再看(f)数组,边界很容易理解?只有一个数,并且这个数满足限制那方案数肯定为(1)

    ​最不好理解的应该就是转移了吧(蒟蒻当初在这里卡了很久).程序描述的其实是酱紫一个方程:

    (f[S] = sum f[x]),其中集合(x)为集合(S)去掉一个元素后得来的

    ​这样应该就很明了了吧?可是为什么是对的呢?

    ​对于一个集合(f[x]),你可以将去掉的那个元素加在每一个合法方案的最末尾,因为(sum)满足限制条件,所以(f[x])的合法方案任然是合法方案,因此加入我们枚举的元素后(f[x])的值不会有变动,所以转移方程是正确的


  • 相关阅读:
    全站HTTPS底层实现原理
    python十个实战项目
    CP30,DBCP数据源配置
    FileUtils
    我的HttpClients工具
    Hibernate如何一个类映射两个表
    SSH2中实例化不了Action的一个原因
    二进制实现权限的分配管理
    myclips常用快捷键
    Hibernate 的*.hbm.xml文件的填写技巧
  • 原文地址:https://www.cnblogs.com/colazcy/p/11514767.html
Copyright © 2011-2022 走看看