首页 > 技术文章 > 集合选数

fenghaoran 2017-03-07 22:31 原文

这是题目

大概就是让你找方案数嘛。开始我还以为是一道规律题,然后有愉快地打了一个暴搜打表。

找了十分钟没找出来。www.oeis.org。结果... ...

这是表

半点规律没有。然后想了想DP,想不出线性或带log的。

最后实在做不出来了,于是问了个大犇。大犇说这道题要用矩形。尼玛没在逗我。

把题目意思转换一下嘛。就是有了X,就不能有2X和3X。

然后依大犇所言构造一个介样的矩形:

1 3 9 27
2 6 18 54
4 12 36 ...
8 24 72 ...
16 48 ... ...

 

这样的话就构造出一个矩阵,满足 A[I][J]=2*A[I-1][J]=3*A[I][J-1];

然后你就会发现,对于一个合法的方案,你选择了一个点,它的上下左右的点都不能选。

然后想起炮兵阵地这道题,状压DP即可求出解(代码甚至更简单)。

注意到这个矩阵内没有5,7,10... ... ,即以它们为左上角的点的方案没有算进去,于是开vis数组。因为各个矩阵内的数字互不影响(因为它们的基数不同),所以用乘法原理。

代码什么的看看就好了,毕竟这题思维偏重。

 1     #include    <iostream>  
 2     #include    <cstdio>  
 3     #include    <cstdlib>  
 4     #include    <algorithm>  
 5     #include    <vector>  
 6     #include    <cstring>  
 7     #define LL long long int  
 8     #define ls (x << 1)  
 9     #define rs (x << 1 | 1)  
10     #define fa (x >> 1)  
11     #define MID int mid=(l+r)>>1  
12     #define max(a,b) (a>b?a:b)  
13     #define min(a,b) (a<b?a:b)  
14     #define MOD 1000000001  
15     using namespace std;  
16     LL n,vis[101010],f[110][2049],a[21][21],Ans=1,line[40],tmp;  
17     LL gi()  
18     {  
19         LL x=0,res=1;char ch=getchar();  
20         while(ch!='-' && (ch>'9' || ch<'0'))ch=getchar();  
21         if(ch=='-')res=-1,ch=getchar();  
22         while(ch<='9'&&ch>='0')x=(x<<3)+(x<<1)+ch-48,ch=getchar();  
23         return x*res;  
24     }  
25     LL calc(LL x)  
26     {  
27         a[1][1]=x;  
28         for(int i=1;;++i)  
29         {  
30             if(i!=1)  
31             {  
32                 a[i][1]=a[i-1][1]*2;  
33                 if(a[i][1]>n)  
34                     {tmp=i-1;break;}  
35             }  
36             vis[a[i][1]]=1;  
37             for(int j=2;;++j)  
38             {  
39                 a[i][j]=a[i][j-1]*3;  
40                 if(a[i][j]>n)  
41                     {line[i]=j-1;break;}  
42                 vis[a[i][j]]=1;  
43             }  
44         }  
45         line[0]=1;  
46         for(int i=0;i<=tmp;++i)  
47             for(int j=0;j<(1<<line[i]);++j)  
48                 f[i][j]=0;  
49         line[tmp+1]=0;f[tmp+1][0]=0;f[0][0]=1;  
50         for(int i=0;i<=tmp;++i)  
51         {  
52             for(int j=0,k1=1<<line[i];j<k1;++j)  
53             {  
54                 if(f[i][j])  
55                 {  
56                     if(j & j>>1)continue;  
57                     for(int k=0,k2=1<<line[i+1];k<k2;++k)  
58                     {  
59                         if(j&k)continue;  
60                         f[i+1][k]=(f[i+1][k]+f[i][j])%MOD;  
61                     }  
62                 }  
63             }  
64         }  
65         return f[tmp+1][0];  
66     }  
67     int main()  
68     {  
69         n=gi();  
70         for(LL i=1;i<=n;++i)  
71             if(!vis[i])  
72                 Ans=(Ans*calc(i))%MOD;  
73         cout<<Ans;  
74     }  

 

推荐阅读