并不对劲的bzoj5342:loj2554:uoj401:p4566: [Ctsc2018]青蕈领主
题目大意
\(T\)(\(T\leq100\))组询问
有\(1\)到\(n\)(\(n\leq50000\))这\(n\)个整数组成的一个排列
定义这个排列的一个子区间是“连续”的,当且仅当这个子区间在位置上和在值域上都是连续的
分别给出这个排列以每个位置\(i\)为右端点的最长“连续”子区间的长度\(l_i\),问有多少个排列满足这个条件
题解
发现这些最长“连续”子区间一定是相互包含或相离的,不会相交
用反证法:假设有\(x<y\),\(x-l_x+1< y-l_y+1\)且\(y-l_y+1< x\),那么\(x-l_x+1\)到\(x\)这一段和\(y-l_y+1\)到\(y\)这一段在值域上连续,那么\(x-l_x+1\)到\(y-l_y+1\)、\(y-l_y+1\)到\(x\)、\(x\)到\(y\)这三段能拼成值域上连续的一段,这样\(x-l_x+1\)到\(y\)就是连续的,以\(y\)为右端点的最长“连续”子区间长度至少\(y-x+l_x\),显然\(y-x+l_x>l_y\),与题意不符
这样就可以将每个位置按以该位置为右端点的最长“连续”子区间的包含关系建成一棵树,而且判断无解也变得十分简单,当有相交的最长“连续”子区间或\(l_n\neq n\)时无解
建出树后,会发现对于每个点\(x\),\(x\)对应的区间相当于每个儿子对应的区间和位置\(x\)上的数拼成的
因为\(x\)的儿子对应的区间都是“连续”的,所以可以把每个儿子看成一个点,点\(x\)的子树的方案数就是所有儿子的方案数乘以把每个儿子看成一个点后满足某些性质的排列数
“满足某些性质的排列”指一些除了整个排列是“连续”的以外,任何一个长度大于\(1\)的子区间都不“连续”的排列,称满足该性质的排列是合法排列
设\(f_i\)表示长度为\(i+1\)的合法排列数
手算可得,\(f_0=1\),\(f_1=2\)
考虑递推求\(f_i\),即已有一个由\(1\)到\(i\)组成的排列,加入\(i+1\),使它合法
有这样两种可能:
一、\(1\)到\(i\)组成的排列合法
\(i+1\)只要不放到\(i\)旁边就行,\(1\)到\(i\)组成的排列一共有\(i+1\)个缝隙,去掉与\(i\)相邻的两个,还剩\(i-1\)个
所以这一部分是\((i-1)*f_{i-1}\)个
二、\(1\)到\(i\)组成的排列不合法
会发现加入\(i+1\)顶多将一个多余的“连续”子区间“打断”,那么就可以看成求有一个长度为\(i\)的排列,该排列只有一个长度大于\(1\)的“连续”子区间,且该子区间内部没有“连续”子区间(即该子区间合法),将\(i+1\)放到这个“连续”合法子区间内的一个位置把这个“连续”合法子区间“打断”
假设“连续”子区间长度为\(j\)
会发现这个问题非常不好解决,那么可以从结果来倒着想:
从这个排列中去掉\(i+1\)后,这个排列只有一个子区间是“连续”的,那么将该子区间缩成一个点,整个排列就变成了一个长度为\(i-j+1\)的合法排列
再把这个过程正过来,就变成了:
(1)生成一个长度为\(i-j+1\)的合法排列
(2)选择一个点,不能选\(i-j+1\)或\(i-j\)
(3)让被选的点变成一个长度为\(j\)的“连续”排列,再加入\(i+1\)这个数——会发现这个过程难以计算,那么还是从结果考虑——结果是一个长度为\(j+1\)的由\(1\)到\(j\)和\(i+1\)合法排列,它去掉\(i+1\)后一定是个长度为\(j\)的“连续”合法子区间(一个长度为\(j\)的由\(1\)到\(j\)的一定是“连续”的)——那么完全可以看成生成一个长度为\(j+1\)的合法排列
这个过程每一步的影响是:
(1)长度为\(i-j+1\)的合法排列数,\(f_{i-j}\)
(2)在\(i-j-1\)个数中选一个,\(i-j-1\)
(3)长度为\(j+1\)的合法排列数,\(f_j\)
在加入\(i+1\)前,“连续”子区间长度为\(j\)的长度为\(i+1\)的合法排列数为\((i-j-1)*f_j*f_{i-j}\)
\(j\)的取值范围是多少呢?
要想使\(1\)到\(i\)组成的排列不合法,多余的“连续”子区间的长度\(j\)至少为\(2\)
要想使\(i-j-1\)个可选的数中至少有一个,\(i-j-1\geq1\),即\(j\leq i-2\)
所以这一部分是$$\sum_{j=2}^{i-2}{(i-j-1)f_jf_{i-j}}$$
这两部分一共有$$f_i=(i-1)f_{i-1}+\sum_{j=2}^{i-2}{(i-j-1)f_j*f_{i-j}}$$
现在想必是可以进行\(\Theta(n^2)\)的递推了,能否进行优化呢?
后面的部分分治FFT解决,前面的部分在分治到左端点等于右端点时直接加到下一项就行
这样就完了?想必没有
会发现在计算完\([l,m]\)这一段后,可能会出现\(i\in[m+1,r],j\in[l,m]\),使\(i-j\in[m+1,r]\),显然此时\(f_{i-j}\)的值还未算出来
这时就得把后面的部分拆成两部分:
\]
这就能卷了吧?
#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 50010
#define maxlen (maxn<<2)
#define LL long long
#define mi (L+R>>1)
#define lim 80
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int a[maxlen],b[maxlen],c[maxlen],r[maxlen],lena,lenb,lenc,len,f[maxn],no;
int t,n,l[maxn];
const LL mod=998244353;
int mul(int x,int y){int ans=1;while(y){if(y&1)ans=(LL)ans*(LL)x%mod;x=(LL)x*(LL)x%mod;y>>=1;}return ans;}
void dnt(int *u,int f)
{
rep(i,1,lenc)if(i<r[i])swap(u[i],u[r[i]]);
for(int i=1;i<lenc;i<<=1)
{
int wn=mul(3,(mod-1)/(i<<1));
if(f==-1)wn=mul(wn,mod-2);
for(int j=0;j<lenc;j+=(i<<1))
{
int w=1,x,y;
rep(k,0,i-1)
x=u[j+k],y=(LL)w*(LL)u[i+j+k]%mod,u[j+k]=(x+y)%mod,u[j+i+k]=(x-y+mod)%mod,w=(LL)w*(LL)wn%mod;
}
}
if(f==-1)
{
int inv=mul(lenc,mod-2);
rep(i,0,lenc-1)u[i]=(LL)u[i]*(LL)inv%mod;
}
}
void work(int L,int R)
{
if(L==R)
{
if(L==1)return;
f[L]=(f[L]+(LL)f[L-1]*(LL)(L-1)%mod)%mod;
f[L]=(f[L]-(LL)(L-2)*(LL)f[L-1]%mod*(LL)f[1]%mod+mod)%mod;
return;
}
work(L,mi);
if(R-L<=lim)
{
rep(i,mi+1,R)
{
rep(j,i-mi,min(mi,i-L))
f[i]=((LL)f[i]+(LL)f[j]*(LL)f[i-j]%mod*(LL)(j-1)%mod)%mod;
rep(j,i-mi,min(i-L,L-1))
f[i]=((LL)f[i]+(LL)f[j]*(LL)f[i-j]%mod*(LL)(i-j-1)%mod)%mod;
}
}
else
{
len=lena=lenb=0;lenc=1;
rep(i,1,min(R-L,mi))a[lena++]=(LL)(i-1)*(LL)f[i]%mod;
rep(i,L,mi)b[lenb++]=f[i];
while(lenc<lena+lenb-1)lenc<<=1,len++;
rep(i,1,lenc)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
dnt(a,1),dnt(b,1);
rep(i,0,lenc-1)c[i]=(LL)a[i]*(LL)b[i]%mod;
dnt(c,-1);
rep(i,mi+1,R)f[i]=(f[i]+c[i-L-1])%mod;
rep(i,0,lenc)a[i]=b[i]=c[i]=0;
len=lena=lenb=0;lenc=1;
rep(i,1,min(R-L,L-1))a[lena++]=f[i];
rep(i,L,mi)b[lenb++]=(LL)(i-1)*(LL)f[i]%mod;
while(lenc<lena+lenb-1)lenc<<=1,len++;
rep(i,1,lenc)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
dnt(a,1),dnt(b,1);
rep(i,0,lenc-1)c[i]=(LL)a[i]*(LL)b[i]%mod;
dnt(c,-1);
rep(i,mi+1,R)f[i]=(f[i]+c[i-L-1])%mod;
rep(i,0,lenc)a[i]=b[i]=c[i]=0;
}
work(mi+1,R);
}
int getans(int L,int R)
{
int ans=1,nums=0;
dwn(i,R-1,L)
{
int x=i-l[i]+1;
if(x<L){no=1;return 0;}
int tmp=getans(x,i);
if(no==1)return 0;
ans=(LL)ans*(LL)tmp%mod;
nums++; i=x;
}
ans=(LL)ans*(LL)f[nums]%mod;
return ans;
}
int main()
{
t=read(),n=read();
f[0]=1;
f[1]=2;
work(2,n);
while(t--)
{
no=0;
rep(i,1,n)l[i]=read();
if(l[n]!=n){puts("0");continue;}
int ans=getans(1,n);
write(ans);
}
return 0;
}
并不对劲的bzoj5342:loj2554:uoj401:p4566: [Ctsc2018]青蕈领主的更多相关文章
- [CTSC2018]青蕈领主
[CTSC2018]青蕈领主 题解 首先,连续段要知道结论: 连续段要么不交,要么包含 所以是一棵树!每个位置的father是后面第一个包含它的 树形DP! 设dp[x],x为根的子树,(设管辖的区间 ...
- Loj #2554. 「CTSC2018」青蕈领主
Loj #2554. 「CTSC2018」青蕈领主 题目描述 "也许,我的生命也已经如同风中残烛了吧."小绿如是说. 小绿同学因为微积分这门课,对"连续"这一概 ...
- bzoj5342 CTSC2018 Day1T3 青蕈领主
首先显然的是,题中所给出的n个区间要么互相包含,要么相离,否则一定不合法. 然后我们可以对于直接包含的关系建出一棵树,于是现在的问题就是给n个节点分配权值,使其去掉最后一个点后不存在非平凡(长度大于1 ...
- UOJ#401. 【CTSC2018】青蕈领主 分治,FFT
原文链接www.cnblogs.com/zhouzhendong/p/UOJ401.html 题解 首先,对于一个排列,它的连续段一定只有包含关系,没有相交关系. 我们可以据此得到一棵表示连续段的树. ...
- LOJ 2554 「CTSC2018」青蕈领主——结论(思路)+分治FFT
题目:https://loj.ac/problem/2554 一个“连续”的区间必然是一个排列.所有 r 不同的.len 最长的“连续”区间只有包含.相离,不会相交,不然整个是一个“连续”区间. 只有 ...
- uoj#401. 【CTSC2018】青蕈领主(分治FFT)
传送门 话说分治\(FFT\)是个啥子啊--还有题目里那字好像念(蕈xùn) 首先考虑无解的情况:区间相交或者\(L_n\neq n\) 这两个都可以感性理解一下 所以区间之间只会有包含关系,我们把每 ...
- 并不对劲的bzoj5341:loj2553:uoj400:p4565:[Ctsc2018]暴力写挂
题目大意 有两棵\(n\)(\(n\leq366666\))个节点的树,\(T\)和\(T'\),有边权 \(dep(i)\)表示在\(T\)中\(i\)号点到\(1\)号点的距离,\(dep'(i) ...
- 并不对劲的bzoj5340:loj2552:uoj399:p4564: [Ctsc2018]假面
题目大意 有\(n\)(\(n\leq200\))个非负整数\(m_1,m_2,...,m_n\)(\(\forall i\in[1,n],m_i\leq100\)),有\(q\)(\(q\leq2* ...
- CTSC2018 & APIO2018 颓废 + 打铁记
CTSC2018 & APIO2018 颓废 + 打铁记 CTSC 5 月 6 日 完美错过报道,到酒店领了房卡放完行李后直接奔向八十中拿胸牌.饭票和资料.试机时是九省联考的题,从来没做过,我 ...
随机推荐
- [USACO13NOV]空荡荡的摊位Empty Stalls
题目描述 Farmer John's new barn consists of a huge circle of N stalls (2 <= N <= 3,000,000), numbe ...
- 【LibreOJ10121】与众不同(RMQ,二分)
题意: 思路: C++ #include<map> #include<set> #include<cmath> #include<cstdio> #in ...
- BZOJ1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害
n<=3000个点m<=20000条无向边的图,有p<=n个出发点,每个出发点都不可拆,现拆一些点使每个出发点都不能到达点1,求最小点数. 简单的最小割.每个点拆成两个x和y,无向边 ...
- Android视图组成View
视图组成View 创建时间: 2013-9-13 10:51 更新时间: 2013-9-13 11:04
- 利用PHP SOAP实现WEB SERVICE[转载]
php有两个扩展可以实现web service,一个是NuSoap,一个是php 官方的soap扩展,由于soap是官方的,所以我们这里以soap来实现web service.由于默认是没有打开soa ...
- 修改textfield的占位符颜色
[self.titleField setValue:UIColorFromHEXWithAlpha(0x999999, 1) forKeyPath:@"_placeholderLabel.t ...
- Wannafly模拟赛2 C alliances(dfs序+二分)
题目 https://www.nowcoder.com/acm/contest/4/C 题意 由n个点组成一个树,有m个帮派,每个帮派由一些个点组成,这些点以及它们两两路径上的所有点都属于该帮派的管辖 ...
- 2017多校Round3(hdu6056~hdu6066)
补题进度:7/11 1001 待填坑 1002 待填坑 1003(set) 题意: 给定长度为n(n<=5e5)的数组(是n的一个排列)和一个整数k(k<=80),f[l,r]定义为区间[ ...
- java内存区域和对象的产生
一直被java中内存组成弄的头晕眼花,这里总结下都有哪些,先上图片 程序计数器 小块内存,线程执行字节码的信号指示器,以此获取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复都要依赖他 ...
- 转:ORACLE存储过程笔记1----基本语法(以及与informix的比较)
一.基本语法(以及与informix的比较) create [or replace] procedure procedure_name (varible {IN|OUT|IN OUT} type) ...