码迷,mamicode.com
首页 > 其他好文 > 详细

【题解】计数

时间:2020-02-22 10:12:11      阅读:82      评论:0      收藏:0      [点我收藏+]

标签:inline   ons   快速   范围   pac   class   res   amp   out   

题目大意:给一个长度为\(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\n";
        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\n";
        Mat AA=qpow(w,n-m);
    //  cout<<"qwq\n";
        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;
}

【题解】计数

标签:inline   ons   快速   范围   pac   class   res   amp   out   

原文地址:https://www.cnblogs.com/h-lka/p/12343883.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!