【状压DP】BZOJ2734 [HNOI2012]集合选数
    
  
      
      
     
    
      
        题面在这里
一开始看毫无头绪,可以建立这样一个矩阵: \[
x\ \ 3x\ \ 9x \dots \\
2x\ \ 6x\ \ 18x \dots  \\
4x\ \ 12x\ \ 36x \dots \\
\dots
\] 然后就是不能取相邻格子,因为\(logn\)比较小,直接状压就好了……
复杂度有点玄学啊……
卡了好久才过
示例程序:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 
 | #include<cstdio>#include<cstring>
 #define cl(x,y) memset(x,y,sizeof(x))
 typedef long long ll;
 
 const int MOD=1e9+1,maxn=20,maxm=13,maxs=1<<13;
 int n,e,N,M;
 ll f[maxn][maxs],pw2[maxn],pw3[maxn],ans;
 void maker(){
 N=M=1;pw2[0]=pw3[0]=1;
 for (int i=1;pw2[i-1]*2<=n;i++) pw2[i]=pw2[i-1]*2,N++;
 for (int i=1;pw3[i-1]*3<=n;i++) pw3[i]=pw3[i-1]*3,M++;
 }
 int highbit(int j) {for (int t=M;t;t--) if (j&(1<<t-1)) return t;return 0;}
 ll DP(int x){
 N=M=1;
 for (int i=x;i*2<=n;i*=2) N++;
 for (int i=x;i*3<=n;i*=3) M++;
 for (int i=1;i<=N;i++)
 for (int j=0;j<(1<<M);j++) f[i][j]=0;
 f[0][0]=1;
 for (int i=1;i<=N;i++)
 for (int j=0;j<(1<<M);j++){
 if (j&(j>>1)) continue;ll w=pw2[i-1]*pw3[highbit(j)-1]*(j!=0);
 if (w>n||x*w>n) break;
 for (int k=0;k<(1<<M);k++)
 if (!(k&j)) (f[i][j]+=f[i-1][k])%=MOD;
 }
 ll res=0;
 for (int j=0;j<(1<<M);j++) (res+=f[N][j])%=MOD;
 return res;
 }
 int main(){
 scanf("%d",&n);
 maker(); ans=1;
 for (int i=1;i<=n;i++)
 if (i%2!=0&&i%3!=0) (ans*=DP(i))%=MOD;
 printf("%lld",ans);
 return 0;
 }
 
 |