bzoj5342 CTSC2018 Day1T3 青蕈領主

首先顯然的是,題中所給出的n個區間要麼互相包含,要麼相離,不然必定不合法。ios

而後咱們能夠對於直接包含的關係建出一棵樹,因而如今的問題就是給n個節點分配權值,使其去掉最後一個點後不存在非平凡(長度大於1)的連續區間。ide

咱們發現這個方案數和不存在不通過最大(小)值的非平凡連續區間的排列數是等價的。spa

因而咱們考慮$f[n]$爲長度爲$n+1$的答案,咱們考慮去掉最小值。code

若是合法,那麼必然是$f[n-1]$中的一種狀況,而這時咱們要將最小值插進去,咱們發現,只要不插在次小值旁邊就都是合法的,因而這部分的貢獻就是$(n-1) \cdot f[n-1]$。blog

不然,咱們考慮去掉後的序列中的極長的不通過最大值的非平凡連續區間長度爲i,咱們如今要將最小值插進去,而後知足這裏面離散後沒有一個不通過最小值的非平凡連續區間,這是$f[i]$,而後這段區間權值的取值能夠取遍$3~n$,就有$n-i-1$種方案,而後咱們把他縮成一個點,如今要剩下的點合法,就是$f[n-i]$,這部分的貢獻就是$\sum_{i=2}^{n-2}{f[i] \cdot f[n-i] \cdot (i-1)}$string

而後就能夠愉快的cdq+fft啦。it

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define mod 998244353
 7 #define N 133333
 8 using namespace std;
 9 int f[N],T,n,l[N],q[N],top,ans,cnt,flag;
10 int len,inv,rev[N],a[N],b[N],tmp1[N],tmp2[N];
11 int qp(int a,int b){
12     int c=1;
13     for(;b;b>>=1,a=1ll*a*a%mod)
14         if(b&1)c=1ll*c*a%mod;
15     return c;
16 }
17 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
18 void ntt(int *a,int o){
19     register int i,j,k,dan,now,t;
20     for(i=0;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
21     for(k=2;k<=len;k<<=1){
22         dan=qp(3,o==1?(mod-1)/k:(mod-1-(mod-1)/k));
23         for(i=0;i<len;i+=k){
24             now=1;
25             for(j=0;j<(k>>1);j++,now=1ll*now*dan%mod){
26                 t=1ll*a[i+j+(k>>1)]*now%mod;
27                 a[i+j+(k>>1)]=(a[i+j]-t+mod)%mod;
28                 a[i+j]=(a[i+j]+t)%mod;
29             }
30         }
31     }
32     if(o==-1){for(i=0;i<len;i++)a[i]=1ll*a[i]*inv%mod;}
33 }
34 void mul(int *a,int *b,int *c,int l1,int l2){
35     for(len=1;len<=l1+l2;len<<=1);
36     for(int i=0;i<len;i++){
37         if(i&1)rev[i]=(rev[i>>1]>>1)|(len>>1);
38         else rev[i]=rev[i>>1]>>1;
39     }
40     inv=qp(len,mod-2);
41     for(int i=0;i<l1;i++)tmp1[i]=a[i];
42     for(int i=l1;i<len;i++)tmp1[i]=0;
43     for(int i=0;i<l2;i++)tmp2[i]=b[i];
44     for(int i=l2;i<len;i++)tmp2[i]=0;
45     ntt(tmp1,1);ntt(tmp2,1);
46     for(int i=0;i<len;i++)c[i]=1ll*tmp1[i]*tmp2[i]%mod;
47     ntt(c,-1);
48 }
49 void cdq(int l,int r){
50     if(l==r){
51         UPD(f[l],1ll*f[l-1]*(l-1)%mod);
52         return ;
53     }
54     int mid=(l+r)>>1;
55     cdq(l,mid);
56     for(int i=l;i<=mid;i++){
57         a[i-l]=1ll*f[i]*(i-1)%mod;
58         b[i-l]=f[i];
59     }
60     mul(a,b,a,mid-l+1,mid-l+1);
61     for(int i=max(l<<1,mid+1);i<=r;i++)
62         UPD(f[i],a[i-(l<<1)]);
63     if(l!=2){
64         for(int i=2;i<=min(l-1,r-l);i++)a[i-2]=f[i];
65         for(int i=l;i<=mid;i++)b[i-l]=f[i];
66         mul(a,b,a,min(l-1,r-l)-1,mid-l+1);
67         for(int i=max(l+2,mid+1);i<=r;i++)
68             UPD(f[i],1ll*a[i-l-2]*(i-2)%mod);
69     }
70     cdq(mid+1,r);
71 }
72 int main(){
73     scanf("%d%d",&T,&n);
74     f[0]=1;f[1]=2;
75     cdq(2,n-1);
76     while(T--){
77         ans=1;top=0;
78         for(int i=1;i<=n;i++)
79             scanf("%d",&l[i]);
80         if(l[n]!=n){puts("0");continue;}
81         for(int i=1;i<=n;i++){
82             cnt=flag=0;
83             while(top&&i-l[i]+1<=q[top]){
84                 if(i-l[i]+1>q[top]-l[q[top]]+1){flag=1;break;}
85                 top--,cnt++;
86             }
87             if(flag==1)break;
88             ans=1ll*ans*f[cnt]%mod;
89             q[++top]=i;
90         }
91         if(flag)puts("0");
92         else printf("%d\n",ans);
93     }
94 }
View Code
相關文章
相關標籤/搜索