bzoj2734:[HNOI2012]集合选数(状压DP)

本文介绍了一种使用状态压缩动态规划(状压DP)的方法来解决一个特定的矩阵中选择不相邻元素的问题。通过将序列转化为特殊矩阵,并利用状压DP技巧,解决了在矩阵中选取不相邻元素的所有可能性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  菜菜的喵喵题~

  化序列为矩阵!化腐朽为神奇!左上角为1,往右每次*3,往下每次*2,这样子就把问题转化成了在矩阵里选不相邻的数有几种可能。

  举个矩阵的例子

  1 3 9 27
  2 6 18 54
  4 12 36 108

  这样最多11列,最多17行,那么方案数就可以用状压了。 

  但是我们会发现,矩阵里没有5,所以我们要把5作为左上角再算一次答案,最后把所有矩阵的答案用乘法原理乘起来就好

#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
#define MOD(x) ((x)>=mod?(x)-mod:(x))
using namespace std;
const int maxn=500010,mod=1e9+1;
int n,ans,cnth;
int f[20][1<<11],cntl[20];
bool v[maxn];
inline void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;
}
inline int find(int x)
{
    cnth=0;memset(cntl,0,sizeof(cntl));
    for(int i=1,fir=x;fir<=n;i++,fir*=2,cnth++)
    for(int j=1,sec=fir;sec<=n;j++,sec*=3,cntl[i]++)v[sec]=1;
    f[0][0]=1;
    for(int i=1;i<=cnth;i++)for(int j=0;j<=(1<<cntl[1])-1;j++)f[i][j]=0;
    for(int i=1;i<=cnth;i++)
    for(int j=0;j<(1<<cntl[i]);j++)
    if(!(j&(j>>1)))
    for(int k=0;k<(1<<cntl[i-1]);k++)
    if(!(k&(k>>1)))if(!(j&k))f[i][j]=MOD(f[i][j]+f[i-1][k]);
    int sum=0;
    for(int i=0;i<=(1<<cntl[cnth])-1;i++)sum=MOD(sum+f[cnth][i]);
    return sum;
}
int main()
{
    read(n);ans=1;
    for(int i=1;i<=n;i++)
    if(!v[i])ans=1ll*ans*find(i)%mod;
    printf("%d\n",ans);
}
View Code

转载于:https://www.cnblogs.com/Sakits/p/7693341.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值