bzoj5342 CTSC2018 Day1T3 青蕈领主

首先显然的是,题中所给出的n个区间要么互相包含,要么相离,否则一定不合法。

然后我们可以对于直接包含的关系建出一棵树,于是现在的问题就是给n个节点分配权值,使其去掉最后一个点后不存在非平凡(长度大于1)的连续区间。

我们发现这个方案数和不存在不经过最大(小)值的非平凡连续区间的排列数是等价的。

于是我们考虑$f[n]$为长度为$n+1$的答案,我们考虑去掉最小值。

如果合法,那么必然是$f[n-1]$中的一种情况,而这时我们要将最小值插进去,我们发现,只要不插在次小值旁边就都是合法的,于是这部分的贡献就是$(n-1) cdot f[n-1]$。

否则,我们考虑去掉后的序列中的极长的不经过最大值的非平凡连续区间长度为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)}$

然后就可以愉快的cdq+fft啦。

 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
",ans);
93     }
94 }
View Code
原文地址:https://www.cnblogs.com/Ren-Ivan/p/9076202.html