luogu P1357 花园

传送门

先考虑朴素dp,设\(f_{i,j}\)表示推了\(i\)次,前\(m\)个点的状态为二进制数\(j\)(这里记放C为1),转移的时候枚举下一位放什么,还要考虑是否满足C的个数\(\leq k\)

不过这个东西是环形的,考虑拆环为链,即找出所有合法状态\(j\),对于每个\(j\)初始化\(f_{0,j}=1\),然后从\(m+1\)位开始放,推\(n\)次,这个\(j\)的答案为\(f_{n,j}\)

因为\(n\)很大,同时\(j\)状态不超过32个,矩乘优化即可

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define eps (1e-5)

using namespace std;
const int N=35,mod=1000000007;
il LL rd()
{
    re LL x=0,w=1;re char ch;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
struct martix
{
  int n,m;
  LL a[N][N];
  martix(){}
  il void clear(int nn,int mm)
  {
    n=nn,m=mm;
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
        a[i][j]=0;
  }
  il void init()
  {
    for(int i=0;i<n;i++) a[i][i]=1;
  }
  martix operator * (const martix &b) const
  {
    martix an;
    an.clear(n,b.m);
    for(int i=0;i<n;i++)
      for(int j=0;j<b.m;j++)
        for(int k=0;k<m;k++)
          an.a[i][j]=(an.a[i][j]+a[i][k]*b.a[k][j]%mod)%mod;
    return an;
  }
  martix operator ^ (const LL &bb) const
  {
    martix an,a;
    an.clear(n,m),an.init(),a=*this;
    LL b=bb;
    while(b)
      {
        if(b&1) an=an*a;
        a=a*a;
        b>>=1;
      }
    return an;
  }
}a,b;
LL n;
int nn,m,k;
il void initt()
{
  b.clear(nn,nn);
  for(int i=0;i<nn;i++)
    {
      int ii=(i|1)^1,cn=0;
      while(ii) ++cn,ii-=ii&(-ii);
      int j=i>>1;
      if(cn<=k) b.a[i][j]=1;
      if(cn+1<=k) b.a[i][j|(nn>>1)]=1;
    }
  b=b^n;
}

int main()
{
  n=rd(),m=rd(),k=rd();
  nn=1<<m;
  initt();
  LL ans=0;
  for(int i=0;i<nn;i++)
    {
      a.clear(1,nn);
      a.a[0][i]=1;
      a=a*b;
      ans=(ans+a.a[0][i])%mod;
    }
  printf("%lld\n",ans);
  return 0;
}

转载于:https://www.cnblogs.com/smyjr/p/9741086.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值