[CTSC2018] green mushroom Lord
First of all, we want to know what the conclusion consecutive segments:
Continuous cross section or not, comprising either
So is a tree! each father position is behind it comprises a first
Tree DP!
Provided dp [x], x is the root of the subtree (interval length is set len Territories, i.e. L [X]), with 1 ~ len of fillers to meet the number of programs L
That is, each son inside legitimate,
Son assigned to each reference section, such that together draw a not adjacent son
We will not draw a line together?
So you can put each son as a single point, it became classified as: 1,1,1,1, ... a number of programs len!
Set f [i] denotes a length of 1,1,1,1 .... i + 1 legitimate program sequence number i + 1 is.
$dp[x]=(\Pi dp[son])\times f[L[x]]$
Summarize, we can get $ ans = \ Pi f [| son (x) |] $, $ | son (x) | $ x denotes the number of sons
Request f [n]?
Consider become inverse arrangement!
(I.e. the horizontal and vertical coordinates mapping matrix Significance exchange)
Thus, n + 1 becomes a natural segmentation points.
f [n-1], the value of 1
Either legitimate before.
Either something separate 1
| Son (x) | monotonous stack directly
Note, Poly each clear need to re-resize
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') #define pb push_back #define solid const auto & #define enter cout<<endl #define pii pair<int,int> using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);} template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');} namespace Modulo{ const int mod=998244353; int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;} void inc(int &x,int y){x=ad(x,y);} int sub(int x,int y){return ad(x,mod-y);} int mul(int x,int y){return (ll)x*y%mod;} void inc2(int &x,int y){x=mul(x,y);} int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;} template<class ...Args>il int ad(const int a,const int b,const Args &...args) {return ad(ad(a,b),args...);} template<class ...Args>il int mul(const int a,const int b,const Args &...args) {return mul(mul(a,b),args...);} } using namespace Modulo; namespace Miracle{ const int N=50000+5; const int G=3; const int GI=332748118; int n,T; int L[N]; struct Poly{ vector<int>f; Poly(){f.clear();} il int &operator[](const int &x){assert(x<f.size());return f[x];} il void resize(int n){f.resize(n);} il int size(){return f.size();} il void clear(){f.clear();} il void out(){for(reg i=0;i<(int)f.size();++i) ot(f[i]);putchar('\n');} }f; int rev[8*N]; int init(int n){ int m=0; for(m=1;m<n;m<<=1); for(reg i=0;i<m;++i){ rev[i]=(rev[i>>1]>>1)|((i&1)?m>>1:0); } return m; } void NTT(Poly &f,int c){ int n=f.size(); for(reg i=0;i<n;++i){ if(i<rev[i]) swap(f[i],f[rev[i]]); } for(reg p=2;p<=n;p<<=1){ int gen; if(c==1) gen=qm(G,(mod-1)/p); else gen=qm(GI,(mod-1)/p); for(reg l=0;l<n;l+=p){ int buf=1; for(reg i=l;i<l+p/2;++i){ int tmp=mul(f[i+p/2],buf); f[i+p/2]=ad(f[i],mod-tmp); f[i]=ad(f[i],tmp); buf=mul(buf,gen); } } } if(c==-1){ int iv=qm(n); for(reg i=0;i<n;++i){ f [i] = u (f [i], iv); } } } il Poly operator *(Poly F,Poly G){ int n=init(F.size()+G.size()-1); F.resize(n);G.resize(n); NTT(F,1);NTT(G,1); for(reg i=0;i<n;++i) F[i]=mul(F[i],G[i]); NTT(F,-1); return F; } void division ( you have to, you r) { if(l==0&&r==1){ f[0]=1;f[1]=2;return; } if(l==r){ in [] = ad (f [t], as mul (f [ 1 ], in [the first ], the 2 )); in [] = ad (f [t], composed (the first , in [the first ])); return ; } int mid=(l+r)>>1; divi(l,mid); // cout<<" divi ---------------------------"<<l<<" "<<r<<endl; Poly F,G,K; if(l==0){ // goto s; // cout<<"sol1---- "<<endl; F.resize(mid+1); G.resize(mid+1); for(reg i=1;i<=mid;++i){ F[i]=f[i]; G[i]=mul(f[i],i-1); } // F.out(); // G.out(); // cout<<"hahahaha "<<endl; F=F*G; // F.out(); for(reg i=mid+1;i<=r;++i){ f [i] = to (f [i], F [i]); } // cout<<" over "<<endl; }else{ // cout<<"sol2**** "<<endl; F.resize(mid-l+1); G.resize(r-l+1); for(reg i=0;i<=mid-l;++i){ F[i]=f[i+l]; } for(reg i=1;i<=r-l;++i){ G[i]=mul(f[i],i-1); } // F.out(); // G.out(); // cout<<" mul "<<endl; K=F*G; // cout<<" K "<<endl; // K.out(); for(reg i=mid+1;i<=r;++i){ f [i] = to (f [i], K [i- l]); } F.clear();G.clear(); F.resize(mid-l+1);G.resize(r-l+1); // cout<<F.size()<<" len "<<mid-l+1<<endl; for(reg i=0;i<=mid-l;++i){ F[i]=mul(f[i+l],i+l-1); } // cout<<" OK ? "<<endl; for(reg i=1;i<=r-l;++i){ G[i]=f[i]; } K=F*G; for(reg i=mid+1;i<=r;++i){ f [i] = to (f [i], K [i- l]); } } // s:; // cout<<" end "<<f[3]<<endl; divi(mid+1,r); } int sta[N],top; int main(){ rd (T); rd (n); int m=init(n+1); f.resize(m); divi(0,m-1); // f.out(); while(T--){ for(reg i=1;i<=n;++i) rd(L[i]); top=0; if(L[n]!=n) { puts("0");continue; } int ans=1; bool fl=true; for(reg i=1;i<=n;++i){ int son=0; while(top&&sta[top]-L[sta[top]]+1>=i-L[i]+1) ++son,--top; // cout<<" ii "<<i<<" son "<<son<<endl; if(top){ if(sta[top]>=i-L[i]+1) fl=false; } sta[++top]=i; years = mul (years f [his]); } if(!fl) ans=0; printf("%d\n",ans); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* */
The tree!
Then recursively into sub-problems.
Recursively into sub-problems, the. . . As. . . .
Essentially "cut point" to find a similar structure. Or induction