• 「SNOI2019」


    #4379. 「SNOI2019」纸牌

    题目:

    有一副纸牌。牌一共有 $n$ 种,分别标有 $1, 2, dots , n$,每种有 $C$ 张。故这副牌共有 $nC$ 张。

    三张连号的牌($i, i+1, i+2$)或三张相同的牌 $(i,i,i)$ 可以组成一叠。如果一组牌可以分成若干(包括零)叠,就称其为一组王牌。

    你从牌堆中摸了一些初始牌。现在你想再挑出一些牌组成一组王牌,请问有多少种可能组成的王牌呢?答案对 $998244353$ 取模。

    两组牌相同当且仅当它们含有的每一种牌数量都相同。

    思路:

    看到数据范围 $nle 1e^{18}$ 大概猜到对于没有初始牌的牌堆要么有显然规律,要么就是矩乘。

    对然后就矩乘了。

    因为大于等于 $3$ 张的,我们可以在自己牌堆里自己凑成一组,对于要和其他种牌配对的只需要留至多比前一堆多三张的情况。

    所以我们可以用一个 $3*3​$ 的状态表示最后两个牌堆的情况。

    然后用矩阵表示状态的转移系数。

    对于有初始牌的单独构造矩阵。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1005,p=998244353;
    int c,m,a[N],Lg;LL k[N],n;
    il LL read(){
       LL x,f=1;char ch;
       _(!)ch=='-'?f=-1:f;x=ch^48;
       _()x=(x<<1)+(x<<3)+(ch^48);
       return f*x;
    }
    il int mu(int x,int y){
        return (x+y>=p)?x+y-p:x+y;
    }
    struct Mat{
        int a[11][11];
        Mat friend operator *(Mat t1,Mat t2){
            Mat t3;
            for(int i=0;i<9;i++)for(int j=0;j<9;j++)t3.a[i][j]=0;
            for(int i=0;i<9;i++)for(int j=0;j<9;j++)for(int k=0;k<9;k++)
                t3.a[i][j]=mu(t3.a[i][j],1ll*t1.a[i][k]*t2.a[k][j]%p);
            return t3;
        }
    }Ans,po[70],tmp;
    il void ksm(LL y){
        for(int i=0;i<=Lg;i++)if((1ll<<i)&y)Ans=Ans*po[i];
    }
    int main()
    {
        n=read();c=read();m=read();Lg=log2(n)+1;
        for(int i=1;i<=m;i++)k[i]=read(),a[i]=read();
        for(int i=0;i<3;i++)for(int j=0;j<3;j++)for(int k=0;k<3;k++)
            if(i+j+k<=c)po[0].a[i*3+j][j*3+k]=(c-i-j-k)/3+1;
        for(int i=1;i<=Lg;i++)po[i]=po[i-1]*po[i-1];
        Ans.a[0][0]=1;
        for(int x=1;x<=m;x++){
            ksm(k[x]-k[x-1]-1);//printf("!!%d ",Ans.a[0][0]);
            for(int i=0;i<9;i++)for(int j=0;j<9;j++)tmp.a[i][j]=0;
            for(int i=0;i<3;i++)for(int j=0;j<3;j++)for(int k=0;k<3;k++){
                int now=i+j+k;
                if(now<a[x])now=a[x]+((now-a[x])%3+3)%3;
                if(now<=c)tmp.a[i*3+j][j*3+k]=(c-now)/3+1;
            }
            Ans=Ans*tmp;
        }
        ksm(n-k[m]);
        printf("%d
    ",Ans.a[0][0]);
        return 0;
    }
    View Code
  • 相关阅读:
    Code Review 五问五答
    JavaScript 10分钟入门
    swagger editor使用
    Tyk API网关介绍及安装说明
    Castle 多继承选择
    线程信息的获取和设置
    s3 api接口的调用
    在Hadoop集群上的HBase配置
    OpenStack 单元测试
    在Hadoop集群上的Hive配置
  • 原文地址:https://www.cnblogs.com/Jessie-/p/11015092.html
Copyright © 2020-2023  润新知