【NOI2018]バブルソート

【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 \)合理的です。カテゴリートーク:

  1. \(Q_I <をmaxP \)最初ため、動作しません見つけることができます\(I-1 \)\(のp \)が合理的であるべきちょうどDP各地から塗りつぶしの現在の最大数よりも少ないが、モチアンを記入します知っています、最小数を取得します。\(P_I \)どうやらこのモチアンはハエ記入ない小数の上限である\(P_I \)
  2. \(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;
}

おすすめ

転載: www.cnblogs.com/xzz_233/p/10993623.html