问题:
 《集合论与图论》这门课程有一道作业题,要求同学们求出{\(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;   }    来源:博客园
作者:ALEZ
链接:https://www.cnblogs.com/OIEREDSION/p/11432819.html