1. 程式人生 > >牛客練習賽27 計數

牛客練習賽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;
}