【NOI2018]バブルソート
神の質問ORZ
被験体におけるこの制限は、実際に存在する配列3の長さを減少させません
どのようにそれを行うには辞書式の要件を見ていません。
まず\(O(N ^ 2) \) の再帰式(私はそれはないでしょうあまりにも弱かったです...)
長さ3の配列の不在は、ドロップ・シーケンスは2つの立ち上がりシーケンスに分割することができます。
\([I]、[J F \]) を表し\(Iは\)番号を有している(J \)を\最大値は、これまで満たさより大きい。
上昇が二つの配列に分割することができるので、塗りつぶしを介して充填されたこれらの最大数よりも少なく、容易により大きい充填することができる(立ち上がりシーケンスに丸め)大に小さくなり
次いで、式は転送\(F [I] [J ] = \ sum_ {K \の当量のJ} F [I-1] [K] \)
\(F [I-1] [J] \) 充填から転送さもなければ埋める、記入最大値未満である\(1 \) 、現在の最大値より1大きいを満たすすべての現在の最大値よりも大きい数(大、小)にランク(\ JK)\を
別の条件\(IはのLeq J \を\) 、境界\(F [0] [0] = 1 \) 。
プレフィックス転写式のように書き換えることができる\(F [I] [J] = F [1-I] [J] + F [I]、[J-1] \) 。
だからから、数学の集合論の組み合わせです\((0,0)\)右に行っただけ取っ\を((i、j)は\ ) ラインは触れていません\(Y = X + 1 \を ) のプログラム番号、明らかに\(F [I] [J] = I}はJ-C_を{+ 1 1-I ^ {} {-C_-I + J + I. 1. 1} ^ {} \)、答えは\ (F [N] [N] \)
次に行うにはどのように、辞書編集の要件は、pはqが決定した順序を表し、下限辞書式が表しています。列挙\(Iは\) 、満たすために必要な辞書\を(FORALL \ 1 \のLeq J <I、p_j = Q_j; P_I <Q_I \) 。セット\(をmaxP = \ J = MAX_。1} ^ {ip_i \) 、正面と確認した\(I-1 \)\(P \)合理的です。カテゴリートーク:
- \(Q_I <をmaxP \)最初ため、動作しません見つけることができます\(I-1 \)\(のp \)が合理的であるべきちょうどDP各地から塗りつぶしの現在の最大数よりも少ないが、モチアンを記入します知っています、最小数を取得します。\(P_I \)どうやらこのモチアンはハエ記入ない小数の上限である\(P_I \) 。
- \(Q_I>をmaxP \) 、その後、統計への後のプログラムの数は、に見出すことができる\([ニッケル] F [N - Q_I] \) 。そして、和や接頭辞、\(Fは[N - I + 1] [N ---をmaxP 1。] \) 。
その後、新たに追加されたチェックしたい\(p個の\を)新しい場合は、合理的である\(のp \)が最大値をチェックしていない(のp \)\最小数のオフモチアンかどうかです。ライン上でファック。
#include<bits/stdc++.h>
#define il inline
#define vd void
#define mod 998244353
typedef long long ll;
il ll gi(){
ll x=0,f=1;
char ch=getchar();
while(!isdigit(ch))f^=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?x:-x;
}
il int pow(int x,int y){
int ret=1;
while(y){
if(y&1)ret=1ll*ret*x%mod;
x=1ll*x*x%mod;y>>=1;
}
return ret;
}
int n,p[600010],t[600010];
int fact[1200010],ifact[1200010];
il int C(int n,int m){return 1ll*fact[n]*ifact[m]%mod*ifact[n-m]%mod;}
il int F(int i,int j){return (C(i+j-1,i-1)-C(i+j-1,i+1)+mod)%mod;}
int main(){
int T=gi(),nn=1200000;
fact[0]=1;for(int i=1;i<=nn;++i)fact[i]=1ll*fact[i-1]*i%mod;
ifact[nn]=pow(fact[nn],mod-2);for(int i=nn-1;~i;--i)ifact[i]=1ll*ifact[i+1]*(i+1)%mod;
while(T--){
n=gi();
for(int i=1;i<=n;++i)p[i]=gi();
int maxp=0,ans=0;
for(int i=1,s=0;i<=n;++i){
maxp=std::max(p[i],maxp);
if(maxp==n)break;
ans=(ans+F(n-i+1,n-maxp-1))%mod;
if(p[i]!=maxp&&s+1!=p[i])break;
t[p[i]]=1;while(t[s+1])++s;
}
printf("%d\n",ans);
for(int i=1;i<=n;++i)t[i]=0;
}
return 0;
}