luogu P1357 花园

Posted smyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
",ans);
  return 0;
}

以上是关于luogu P1357 花园的主要内容,如果未能解决你的问题,请参考以下文章

luogu P1357 花园

P1357 花园 状压 矩阵快速幂

P1357 花园

P1357 花园

P1357 花园 (矩阵快速幂+ DP)

[luogu]P1133 教主的花园[DP]