牛客练习赛27 计数

题意:

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值