ポータル
説明
カードのデッキがあります。ブランドがあります\(N \)種が標識されているが、\(1、2、...、\ N-)の各、\(C \)シート。だから、デッキの合計\(NC \)シート。
カード3つの連続番号(\(I、Iは+ 1、I + 2 \) )、または3枚の同一のタイル\((I、I、Iは )\) スタックで構成することができます。カードのセットは、(ゼロを含む)に分割することができる場合と呼ばれるグループに、スタックエース。
あなたは山、いくつかの初期のカードからカードをタッチします。今、あなたはカードの一部を選び出すしたいエースのグループを形成し、エースはそれを作曲何頼むかもしれませんか?答えはする(998 244 353 \)\剰余を。
彼らはそれぞれのカードの量が含まれている場合に限り、二つの同一のカードは同じです。
溶液
この質問は中に発見された\(N \)大きいので、行列の乗算を考えます
私が見つかりました\(、I + 1(Iは 、I + 2)\) そのようなカードを、同じ\(私は\) 、最大で2つの重複
そう考える\を(3 * 3 \)状態が示す現在の数\(私は\)と\(I-1 \)純子の初期量\((0,1,2)\)
列挙することが必要見つけ、どのように次の番号への変換を検討し\(I + 1 \)ストレート開始の数を、それが実行可能になります((I + 1、I \ \ + 1、I + 1)) の数番号
元のタイトル\(DP \)は、ビット行列の乗算を変換しました
いくつかはすでに最初のライセンスを持っているために、我々は転送を分離考えます
遷移行列は、第1の電力を算出することができ、定数を小さく
コード
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define reg register
#define int ll
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int P=998244353,MX=1005;
ll n,C,X,A[MX],K[MX];
int Mul(int x,int y){return (1LL*x*y)%P;}
int Add(int x,int y){return (x+y)%P;}
struct Matrix
{
int a[9][9];
Matrix(){memset(a,0,sizeof a);}
void emp(){for(int i=0;i<9;++i)a[i][i]=1;}
Matrix operator *(Matrix b)
{
Matrix c;
register int i,j,k;
for(k=0;k<9;++k)for(i=0;i<9;++i)for(j=0;j<9;++j)
c.a[i][j]=Add(c.a[i][j],Mul(b.a[i][k],a[k][j]));
return c;
}
}tmp,opt[70],ans;
Matrix OPT(int m)
{
Matrix r;int x=0;r.emp();
for(;m;m>>=1,++x)if(m&1)r=r*opt[x];
return r;
}
signed main()
{
n=read();C=read();X=read();
register int i,j,k,l;
for(i=1;i<=X;++i) K[i]=read(),A[i]=read();
for(i=0;i<3;++i)for(j=0;j<3;++j)for(k=0;k<3;++k)
if(i+j+k<=C)opt[0].a[j*3+k][i*3+j]=1+(C-i-j-k)/3;
for(i=1;i<70;++i) opt[i]=opt[i-1]*opt[i-1];
ans.a[0][0]=1;
for(l=1;l<=X;++l)
{
ans=ans*OPT(K[l]-K[l-1]-1);
memset(tmp.a,0,sizeof tmp.a);
for(i=0;i<3;++i)for(j=0;j<3;++j)for(k=0;k<3;++k)
{
int least=i+j+k;
if(least<A[l]) least=A[l]+((least-A[l])%3+3)%3;
if(least<=C) tmp.a[j*3+k][i*3+j]=1+(C-least)/3;
}
ans=ans*tmp;
}
ans=ans*OPT(n-K[X]);
printf("%lld\n",ans.a[0][0]);
return 0;
}
ブログPaperCloudは、許可なしに、TKSを転載しないでください!