zoukankan      html  css  js  c++  java
  • [P2396] yyy loves Maths VII

    Link:

    P2396 传送门

    Solution:

    一眼能看出$O(n*2^n)$的状压$dp$

    但此题是个卡常题,$n=23/24$的时候就别想过了

    这题算是提供了一种对状压$dp$的优化思路吧

    原来我们要用$n$的时间来查找当前有哪些位为1,然后从这些位来转移

    但实际上可以通过树状数组中$lowbit$函数的方式用$popcount(i)$的复杂度来得到所有的1

    此时总的复杂度降到了$O(sum_{i=1}^{2^n-1} popcount(i))$,实际上就是$O(n*2^{n-1})$

    虽然只减少了1倍的时间,但开个$O2$还是勉强能卡过去

    Tip:使用这种优化时只能从$dp[i^(1<<j)]$向$dp[i]$转移,而不能从$dp[i]$向$dp[i|(1<<j)]$转移了

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAXN=1<<25,MOD=1e9+7;
    int n,dat[MAXN],dp[MAXN],m,m1,m2,lst,t;
    
    void inc(int &a,int b){a=(a+b>=MOD)?(a+b-MOD):a+b;}
    int main()
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d",&dat[1<<i]);
        scanf("%d",&m);
        if(m>=1) scanf("%d",&m1);
        if(m>=2) scanf("%d",&m2);
        
        dp[0]=1;int MAX=(1<<n)-1;
        for(int i=1;i<=MAX;i++)
        {
            lst=i&(-i);
            dat[i]=dat[i^lst]+dat[lst];
            if(dat[i]==m1||dat[i]==m2) continue;
            
            for(t=i;t;t^=lst,lst=t&(-t))
                inc(dp[i],dp[i^lst]);
        }
        printf("%d",dp[MAX]);
        return 0;
    }
  • 相关阅读:
    1292
    explicit_defaults_for_timestamp
    比较好的平台工具
    git回退到指定版本的代码
    解决catalina.out文件过大的方法
    json字符串转化成对象列表数据
    Java LIST做批量分组切割
    Activiti数据库表结构
    MySQL修改数据库时区
    集合工具类的使用
  • 原文地址:https://www.cnblogs.com/newera/p/9282103.html
Copyright © 2011-2022 走看看