题意:
n个数字一个环,每个数字只能是3或7,要求所有相邻的m个数中,7的个数大于等于3的个数,求方案数。
题解:
由于m<=5,用一个数字表示最后m个数的状态,转移方程很好写:
dp[i]->dp[j](j和i都合法,并且二进制下i的后m-1位和j的前m-1位相同)
然后构造转移矩阵,求快速幂
如何保证是环的情况下依据合法?
我们枚举初始状态,2^m种,然后计数时只统计最后状态和初始状态合法的。
教训:
位运算中 & 和 << 不是一个优先级!!
代码:
#include<bits/stdc++.h>
#define N 32
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define mod 998244353
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lower_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
LL n,m,lim;
bool check(int x)
{
return __builtin_popcount(x)>=(m+1)/2;
}
struct Matrix
{
LL a[N][N];
Matrix(){memset(this,0,sizeof(Matrix));}
Matrix operator *(const Matrix x) const
{
Matrix ans;
for(int i=0;i<lim;i++) if (check(i))
for(int j=0;j<lim;j++) if (check(j))
{
for(int k=0;k<lim;k++)
ans.a[i][j]+=a[i][k]*x.a[k][j]%mod;
ans.a[i][j]%=mod;
}
return ans;
}
friend Matrix operator ^(Matrix x,LL y)
{
Matrix ans;
for(int i=0;i<lim;i++) ans.a[i][i]=1;
while(y)
{
if (y&1) ans=ans*x;
x=x*x; y>>=1;
}
return ans;
}
}x;
int main()
{
LL ans=0;
cin>>n>>m; lim=1<<m;
for (int i=0;i<lim;i++)
for (int j=0;j<lim;j++) if (check(j) && check(i) && ( j&((1<<m-1)-1))==(i>>1) )
x.a[j][i]=1;
Matrix f=x^(n-m);
for (int i=0;i<lim;i++)
{
for (int j=0;j<lim;j++)
{
int fg=1;
for (int k=1;k<m;k++)
if (check(((j<<k)|(i>>m-k))&lim-1)) fg++;
if (fg==m) ans=(ans+f.a[i][j])%mod;
}
}
cout<<ans;
}