题解计数
Posted h-lka
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解计数相关的知识,希望对你有一定的参考价值。
题目大意:给一个长度为(n(n<=10^{18}))的环,要求在任意(m)个数中,(3)的数不大于(7)的个数(整个序列由(3,7)构成),问总方案数
(Solution)
介于(n)很大,我们不得不把思路转换到(m)上。
考虑一个状态(j),如果能从状态(i)转移过来,则(j)的方案数可以加上(i)的方案数。
看(n)数据范围,考虑矩阵快速幂。
距震中,([i][j])表示状态(j)可以由(i)转移过来。因为是环,我们枚举所有状态,将它作为起点,(dp)一遍,做完之后对于最后一个状态,要(check)是不是与开头合法。
我们每次只处理一个开头,就把初始矩阵中的([0][i])赋值成(1),最后的矩阵也是一个(1*)状态数的矩阵,值得注意的是,不能只保留有用状态,无用状态是可能转变成有用状态的。
#include<bits/stdc++.h>
using namespace std;
long long n;
int m,ans,cc;
const int mod=998244353;
const int P=mod;
int t=33;
struct Mat{
int A[34][34];
Mat(){
memset(A,0,sizeof(A));
}
Mat operator *(const Mat&B)const {
Mat tmp;
for(int i=0; i<t; i++) {
for(int j=0; j<t; j++) {
for(int k=0; k<t; k++) {
tmp.A[i][j]=(tmp.A[i][j]+1ll*A[i][k]*B.A[k][j]%P)%P;
}
}
}
return tmp;
}
}w,d;
Mat qpow(Mat a,long long b){
Mat c=d;
while(b){
if(b&1)c=c*a;//cout<<"qwq
";
a=a*a;b>>=1;
}
return c;
}
inline int get(int x){
int res=0;
while(x){
if(x&1)res++;
x>>=1;
}
return res;
}
int cnt[500],tot=-1,mp[500];
int use[300];
inline bool check(int x,int y){
// memset(use,0,sizeof(use));
int L=0;
for(int i=m-1;i>=0;--i)use[++L]=x>>i&1;
for(int i=m-1;i>=0;--i)use[++L]=y>>i&1;
for(int i=1;i<=L-m+1;++i){
int r=0;
for(int j=0;j<m;++j)
r+=use[i+j];
if(r>cc)return false;
}
return true;
}
int main(){
scanf("%lld%d",&n,&m);
//memset(cnt,-1,sizeof(cnt));
// memset(mp,-1,sizeof(mp));
cnt[0]=0;
cc=m/2;
t=(1<<m);
for(int i=1;i<(1<<m);++i)cnt[i]=cnt[i-(i&-i)]+1;
int H=(1<<m)-1;
//cout<<cnt[8]<<endl;
for(int i=0;i<(1<<m);++i){
// int nt=cnt[i]>>1;
//if(cnt[nt]>cc)continue;
if(cnt[i]>cc)continue;
int nt=(i<<1)&H;
if(cnt[nt]>cc)continue;
if(cnt[nt]<=cc)w.A[i][nt]=1;
nt|=1;
if(cnt[nt]<=cc)w.A[i][nt]=1;
//状态i所累加的值在mpnt列
}
//for(int i=0;i<tot;++i)d.A[i][0]=1;
/*for(int i=0;i<tot;++i){
memset(d.A,0,sizeof(d.A));
d.A[i][0]=1;
Mat AA=qpow(w,n-m);
//d.A[0][j]=1;
//Mat e=AA*d;
for(int j=0;j<tot;++j)
if(check(cnt[j],cnt[i]))
ans+=AA.A[j][0],ans%=mod;
}*/
for(int i=0;i<(1<<m);++i){
if(cnt[i]>cc)continue;
memset(d.A,0,sizeof(d.A));
d.A[0][i]=1;
//cout<<"qwq
";
Mat AA=qpow(w,n-m);
// cout<<"qwq
";
for(int j=0;j<(1<<m);++j){
if(cnt[j]>cc)continue;
if(check(j,i))ans+=AA.A[0][j],ans%=mod;
}
}
cout<<ans<<endl;
return 0;
}
以上是关于题解计数的主要内容,如果未能解决你的问题,请参考以下文章