[CTSC2018]青蕈领主

题解

首先,连续段要知道结论:

连续段要么不交,要么包含

所以是一棵树!每个位置的father是后面第一个包含它的

树形DP!

设dp[x],x为根的子树,(设管辖的区间长度为len,也即L[x]),用1~len的数填充,满足L的方案数

也就是,每个son内部合法,

给每个son分配标号区间,使得相邻儿子不会再接在一起

不会再接在一起?

所以可以把每个儿子看成单独一个点,就划归成了:1,1,1,1,...len的方案数!

设f[i]表示,长度为i+1的1,1,1,1....i+1的序列的合法方案数。

$dp[x]=(\Pi dp[son])\times f[L[x]]$

归纳一下,可得$ans=\Pi f[|son(x)|]$,$|son(x)|$表示x的儿子个数

求f[n]?

考虑变成排列的逆!

(也就是把映射矩阵的横纵坐标意义交换)

这样,n+1成为了天然的分割点。

f[n-1]中,填入1,

要么之前合法。

要么1分开了一些东西

|son(x)|可以直接单调栈

注意,Poly每次clear需要重新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=;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);(fl==true)&&(x=-x);}
template<class T>il void output(T x){if(x/)output(x/);putchar(x%+'');}
template<class T>il void ot(T x){if(x<) 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=;
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-){int ret=;while(y){if(y&) ret=mul(x,ret);x=mul(x,x);y>>=;}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=+;
const int G=;
const int GI=;
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=;i<(int)f.size();++i) ot(f[i]);putchar('\n');}
}f;
int rev[*N];
int init(int n){
int m=;
for(m=;m<n;m<<=);
for(reg i=;i<m;++i){
rev[i]=(rev[i>>]>>)|((i&)?m>>:);
}
return m;
}
void NTT(Poly &f,int c){
int n=f.size();
for(reg i=;i<n;++i){
if(i<rev[i]) swap(f[i],f[rev[i]]);
}
for(reg p=;p<=n;p<<=){
int gen;
if(c==) gen=qm(G,(mod-)/p);
else gen=qm(GI,(mod-)/p);
for(reg l=;l<n;l+=p){
int buf=;
for(reg i=l;i<l+p/;++i){
int tmp=mul(f[i+p/],buf);
f[i+p/]=ad(f[i],mod-tmp);
f[i]=ad(f[i],tmp);
buf=mul(buf,gen);
}
}
}
if(c==-){
int iv=qm(n);
for(reg i=;i<n;++i){
f[i]=mul(f[i],iv);
}
}
}
il Poly operator *(Poly F,Poly G){
int n=init(F.size()+G.size()-);
F.resize(n);G.resize(n);
NTT(F,);NTT(G,);
for(reg i=;i<n;++i) F[i]=mul(F[i],G[i]);
NTT(F,-);
return F;
}
void divi(int l,int r){ if(l==&&r==){
f[]=;f[]=;return;
}
if(l==r){
f[l]=ad(f[l],mod-mul(f[],f[l-],l-));
f[l]=ad(f[l],mul(l-,f[l-]));
return;
}
int mid=(l+r)>>;
divi(l,mid);
// cout<<" divi ---------------------------"<<l<<" "<<r<<endl;
Poly F,G,K;
if(l==){
// goto s;
// cout<<"sol1---- "<<endl;
F.resize(mid+);
G.resize(mid+);
for(reg i=;i<=mid;++i){
F[i]=f[i];
G[i]=mul(f[i],i-);
}
// F.out();
// G.out();
// cout<<"hahahaha "<<endl;
F=F*G;
// F.out(); for(reg i=mid+;i<=r;++i){
f[i]=ad(f[i],F[i]);
}
// cout<<" over "<<endl;
}else{ // cout<<"sol2**** "<<endl;
F.resize(mid-l+);
G.resize(r-l+);
for(reg i=;i<=mid-l;++i){
F[i]=f[i+l];
}
for(reg i=;i<=r-l;++i){
G[i]=mul(f[i],i-);
}
// F.out();
// G.out();
// cout<<" mul "<<endl;
K=F*G;
// cout<<" K "<<endl;
// K.out(); for(reg i=mid+;i<=r;++i){
f[i]=ad(f[i],K[i-l]);
} F.clear();G.clear();
F.resize(mid-l+);G.resize(r-l+); // cout<<F.size()<<" len "<<mid-l+1<<endl;
for(reg i=;i<=mid-l;++i){
F[i]=mul(f[i+l],i+l-);
}
// cout<<" OK ? "<<endl;
for(reg i=;i<=r-l;++i){
G[i]=f[i];
} K=F*G;
for(reg i=mid+;i<=r;++i){
f[i]=ad(f[i],K[i-l]);
}
}
// s:;
// cout<<" end "<<f[3]<<endl;
divi(mid+,r);
}
int sta[N],top;
int main(){
rd(T);rd(n);
int m=init(n+);
f.resize(m); divi(,m-);
// f.out(); while(T--){
for(reg i=;i<=n;++i) rd(L[i]);
top=;
if(L[n]!=n) {
puts("");continue;
}
int ans=;
bool fl=true;
for(reg i=;i<=n;++i){
int son=;
while(top&&sta[top]-L[sta[top]]+>=i-L[i]+) ++son,--top;
// cout<<" ii "<<i<<" son "<<son<<endl;
if(top){
if(sta[top]>=i-L[i]+) fl=false;
}
sta[++top]=i;
ans=mul(ans,f[son]);
}
if(!fl) ans=;
printf("%d\n",ans);
}
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
*/

树形结构!

然后递归为子问题。

递归为子问题,把。。。看成。。。。

本质就是“缩点”找相似结构。或者归纳

[CTSC2018]青蕈领主的更多相关文章

  1. 并不对劲的bzoj5342:loj2554:uoj401:p4566: [Ctsc2018]青蕈领主

    题目大意 \(T\)(\(T\leq100\))组询问 有\(1\)到\(n\)(\(n\leq50000\))这\(n\)个整数组成的一个排列 定义这个排列的一个子区间是"连续" ...

  2. Loj #2554. 「CTSC2018」青蕈领主

    Loj #2554. 「CTSC2018」青蕈领主 题目描述 "也许,我的生命也已经如同风中残烛了吧."小绿如是说. 小绿同学因为微积分这门课,对"连续"这一概 ...

  3. uoj#401. 【CTSC2018】青蕈领主(分治FFT)

    传送门 话说分治\(FFT\)是个啥子啊--还有题目里那字好像念(蕈xùn) 首先考虑无解的情况:区间相交或者\(L_n\neq n\) 这两个都可以感性理解一下 所以区间之间只会有包含关系,我们把每 ...

  4. bzoj5342 CTSC2018 Day1T3 青蕈领主

    首先显然的是,题中所给出的n个区间要么互相包含,要么相离,否则一定不合法. 然后我们可以对于直接包含的关系建出一棵树,于是现在的问题就是给n个节点分配权值,使其去掉最后一个点后不存在非平凡(长度大于1 ...

  5. UOJ#401. 【CTSC2018】青蕈领主 分治,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ401.html 题解 首先,对于一个排列,它的连续段一定只有包含关系,没有相交关系. 我们可以据此得到一棵表示连续段的树. ...

  6. LOJ 2554 「CTSC2018」青蕈领主——结论(思路)+分治FFT

    题目:https://loj.ac/problem/2554 一个“连续”的区间必然是一个排列.所有 r 不同的.len 最长的“连续”区间只有包含.相离,不会相交,不然整个是一个“连续”区间. 只有 ...

  7. CTSC2018 & APIO2018 颓废 + 打铁记

    CTSC2018 & APIO2018 颓废 + 打铁记 CTSC 5 月 6 日 完美错过报道,到酒店领了房卡放完行李后直接奔向八十中拿胸牌.饭票和资料.试机时是九省联考的题,从来没做过,我 ...

  8. [冬令营模拟]GTSG2018

    上学期没有去 GTSG,于是今天老师让我们来做一下 GTSG2018 Day1 & Day3 Day1 在上午当成一场考试来搞了,Day3 由于锅太多而且 T3 玄学而被放到下午自学... 上 ...

  9. GOOD BYE OI

    大米饼正式退役了,OI给我带来很多东西 我会的数学知识基本都在下面了 博客园的评论区问题如果我看到了应该是会尽力回答的... 这也是我作为一个OIer最后一次讲课的讲稿 20190731 多项式乘法 ...

随机推荐

  1. 因kernel too old 而 centos6.8 升级内核

    因为docker运行centos 的时候,报错了,错误为kernel too old .我看了一下是因为os的内核不行了,需要升级下内核. 查看默认版本: uname -r 忘记截图了,内核大概是2. ...

  2. vim - Vi IMproved, 一个程序员的文本编辑器

    总览 (SYNOPSIS) vim [options] [file ..] vim [options] - vim [options] -t tag vim [options] -q [errorfi ...

  3. unicode_stop - 撤销控制台unicode模式(例如, 回到8-bit模式).

    总览 unicode_stop 描述 unicode_stop 撤销以前 unicode_start(1) 命令的效果, 将显示屏和键盘设回到 8-bit 模式.

  4. 快速读取 C++

    int read() { ; ; char ch=getchar(); ') { if (ch=='-') f=-; ch=getchar(); } ') { x=x*+ch-'; ch=getcha ...

  5. 夯实JavaScript基础之prototype, __proto__, instanceof

    function New(f){ return function(){ var o = {'__proto__': f.prototype}; f.apply(o, arguments); retur ...

  6. java创建一个空白zip

    String zipath = localpath+zipname+".zip"; public static void createNewzip(String zipath) t ...

  7. 50. Set接口和Set的实现类HashSet

    集合分类:-------------------| Collection 单列集合的根接口   ---------------| List 如果实现了List接口的集合类,具备的特点是:有序,可重复- ...

  8. MVC升级后报"当前上下文中不存在ViewBag"错的解决方法

  9. jenkins的安装和启用

    1.下载Jenkins:下载地址:https://jenkins.io/zh/download/ 2.将Jenkins.war包上传到Tomcat的webapps目录下,本次的目录是/usr/loca ...

  10. js的三种消息框alert,confirm,prompt

    原文:http://blog.csdn.net/lixiang0522/article/details/7764730 <html> <head> <script typ ...