zoukankan      html  css  js  c++  java
  • 集合选数 状压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;  
    }  
    
    刀剑映出了战士的心。而我的心,漆黑且残破
  • 相关阅读:
    【NOIP2007】守望者的逃离
    20200321(ABC)题解 by 马鸿儒 孙晨曦
    20200320(ABC)题解 by 王一帆
    20200319(ABC)题解 by 王一帆 梁延杰 丁智辰
    20200314(ABC)题解 by 董国梁 蒋丽君 章思航
    20200309(ABC)题解 by 梁延杰
    20200307(DEF)题解 by 孙晨曦
    20200306(ABC)题解 by 孙晨曦
    20200305(DEF)题解 by 孙晨曦
    20200303(ABC)题解 by 王锐,董国梁
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11432819.html
Copyright © 2011-2022 走看看