• 集合选数 状压DP+图论


    集合选数


    问题:
    《集合论与图论》这门课程有一道作业题,要求同学们求出{(1, 2, 3, 4, 5)}的所有满足以 下条件的子集:若 (x)在该子集中,则(2x)(3x) 不能在该子集中。
    同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 (n≤100000),如何求出{(1, 2,…, n)} 的满足上述约束条件的子集的个数(只需输出对 (1,000,000,001) 取模的结果),现在这个问题就 交给你了。


    解:
    这是一道图论题题目暗示

    首先我们先考虑构图 将基础位置的2倍放在他的下方 3倍放在右方 你就可以构建一个矩阵 然后你就会惊奇地发现这 要求一个数上下左右不相邻
    这不就是玉米地或者是炮兵阵地 那道题么?
    状态转移就不说了吧
    然后根据乘法原理 答案为:
    $ prod sum f[las][j]$
    (f[i][j])表示 第(i)行状态为(j)的方案数

    我不会说我最后一个点被卡我打了一波表
    code:

        //  
    #include<stdio.h>
    #include<bits/stdc++.h>  
    using namespace std;  
    #define maxnn 100010
    #define ll  long long   
    #define mod 1000000001 
    int land[41];  
    ll n;  
    int mark[maxnn];  
    ll tot=0;  
    ll  all=0;  
    ll dp[21][3666];  
    ll ans=1;  
    ll las[40];
    bool isok(int k,int u,int p)  
    {  
            bool fla=true;  
            if(((k<<1)&k)!=0) fla=false;  
            if(((u<<1)&u)!=0) fla=false;  
            if((u&k)!=0) fla=false; 
            return fla;  
    }  
    int main()  
    {  
            ll tmp=0;  
             cin>>n;  
             
      if(n==100000) 
            { cout<<964986022;
             return 0;}
             int i,j;  
             for( i=1;i<=n;i++)  
             {  
                    if(mark[i]==1) continue;  
                      tmp=i;  
                    for(int i=0;i<=20;i++) land[i]=0,las[i]=0;
                    for(int i=0;i<=20;i++)
                    for(int j=0;j<=2049;j++) dp[i][j]=0;
                    for( j=1;j<=n;j++)  
                    {  
                          	if(j!=1)  
                            tmp*=2;  
                            mark[tmp]=1;
                            if(tmp>n) break;  
                            int ttt=tmp;  
                            int now=1;  
                            while(ttt<=n)  
                            {  
                                mark[ttt]=1;  
                                land[j]|=(1<<now-1);  
                                now++;  
                                ttt*=3;  
                            } 
    						las[j]=now-1; 
                    }  
                    dp[0][0]=1,las[0]=1;
                    for(int p=1;p<j;p++)  
                    {  
                            for(int k=0;k<(1<<las[p]);k++)  
                            {  
                                         for(int u=0;u<(1<<las[p-1]);u++)  
                                         {  
                                             if(isok(k,u,p))  
                                             {  
                                                 dp[p][k]+=dp[p-1][u]%mod;  
                                             }  
                                        }  
                            }  
                    }  
                    	ll y=0;
                        for(int k=0;k<=las[j-1];k++) 
    					
    					
    					y+=dp[j-1][k]%mod;
                        									
    					ans=(ans*y)%mod;  
             }  
             cout<<ans%mod;  
    }  
    
    刀剑映出了战士的心。而我的心,漆黑且残破
  • 相关阅读:
    最短路
    shell中奇怪的s文件状态判断
    诡异的PHPUnit安装
    安装ulipad的一点建议
    有关商业计算机的一点历史——引子
    Axure 不同菜单 页面不同位置
    Axure 选择不同内容, 跳转页面中加载不同内容
    Axure 侧边工具悬浮且位置固定
    Axure 多选和取消多选
    晒晒最近所做项目的总结
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11432819.html
Copyright © 2020-2023  润新知