これは割とすんなり。
https://codeforces.com/contest/1861/problem/E
問題
正整数N,Kが与えられる。
以下を満たす整数列Aは何通りか。
- AはN要素で、1~Kの整数値を取る。
- Aをいくつかの連続部分列に分割したとき、1~KのPermutationとなる箇所が最大でK個になる。
解法
以下を求めよう。
dp(n) := n要素並べたとき、K要素の連続部分列が1~KのPermutationとなるのは末尾K要素の時のみ
これは末尾K要素が異なる数列から、prefix m要素がdp(m)のパターンになるものを包除すればよい。
あとはそのような数列をK個並べたケースを求めて行こう。
int N,K; const ll mo=998244353; const int NUM_=400001; static ll fact[NUM_+1],factr[NUM_+1],inv[NUM_+1]; ll comb(ll N_, ll C_) { if(C_<0 || C_>N_) return 0; return factr[C_]*fact[N_]%mo*factr[N_-C_]%mo; } ll modpow(ll a, ll n = mo-2) { ll r=1;a%=mo; while(n) r=r*((n%2)?a:1)%mo,a=a*a%mo,n>>=1; return r; } ll dp[4040]; // 長さNで初めてK個並ぶ ll pat[4040]; void solve() { int i,j,k,l,r,x,y; string s; inv[1]=fact[0]=factr[0]=1; for (int i=2;i<=NUM_;++i) inv[i] = inv[mo % i] * (mo - mo / i) % mo; for (int i=1;i<=NUM_;++i) fact[i]=fact[i-1]*i%mo, factr[i]=factr[i-1]*inv[i]%mo; cin>>N>>K; for(i=K;i<=N;i++) { dp[i]=fact[K]*modpow(K,i-K)%mo; for(j=K;j<i;j++) { if(i-j>=K) { (dp[i]-=dp[j]*modpow(K,i-j-K)%mo*fact[K])%=mo; } else { (dp[i]-=dp[j]*fact[i-j])%=mo; } } dp[i]=(dp[i]%mo+mo)%mo; } ll ret=0; pat[0]=1; FOR(i,N) { for(j=K;i+j<=N;j++) { (pat[i+j]+=pat[i]*dp[j])%=mo; (ret+=pat[i]*dp[j]%mo*modpow(K,N-i-j))%=mo; } } cout<<ret<<endl; }
まとめ
6問回の5問目にしては易しいかも。