首页 > 其他分享 >luogu P4566 [CTSC2018]青蕈领主

luogu P4566 [CTSC2018]青蕈领主

时间:2023-03-14 15:13:55浏览次数:52  
标签:P4566 int luogu long CTSC2018 连续 区间 using define

题面传送门

最后这个转化非常牛逼啊!

首先我们可以证明:一个合法的序列中,这样的极长连续区间不会相交。

Proof:如果相交了,说明相交的区间也是一段连续区间,而每个区间不相交的部分也是连续区间,所以两个区间的并也是连续区间。又因为两个区间都是极长连续区间,因此不会包含,所以与题设的”极长”矛盾。

因此现在区间只剩下相互包含和互不相交两种。把这个建成一个树的结构,可以发现一个区间的儿子覆盖了整个区间,除了最后一个位置。因此如果我们可以求出 \(g_i\) 表示 \(i+1\) 个数排列在一起,除了最后一个位置的连续区间长度为全区间,其余都为 \(1\) 的排列个数,方案数就是 \(\prod{g_{siz_i}}\),其中 \(siz_i\) 表示 \(i\) 的儿子个数。

现在压力来到了 \(g\) 身上。直接对 \(g\) 计数也不好做。考虑对 \(p\) 的转置计数,也即 \(q_{p_i}=i\)。\(p\) 的原来的限制转化过来就是除了包含最大值的连续区间,其余连续区间长度都为 \(1\)。

考虑对 \(2\dots n+1\) 序列插入 \(1\) 来完成 \(n\) 到 \(n+1\) 的转移。分两种情况:

  • 序列原来是合法的区间,那么除了插入在 \(2\) 两边都可以,因此有转移 \(f_{i}\times i\to f_{i+1}\)。
  • 序列原来是不合法的区间,那么原来的连续区间都要包含 \(1\) 的位置,且连续区间中不包含 \(2\) 。枚举最大的连续区间的长度,有转移 \(f_{j}f_{i-j}(j-1)\to f_i\)。

直接暴力\(O(n^2)\) 的 dp 可以有 \(80\) 分。优化的话直接上分治 NTT 就可以做到 \(O(n\log ^2n)\)。注意这里是自己乘自己转移到自己,和普通的分治 NTT 有所不同。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
#define fi first
#define se second
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned long long;
using namespace std;const int N=(1<<18)+5,M=N*100+5,K=N*4+5,mod=998244353,Mod=mod-1;const db eps=1e-9;const ll INF=1e18+7;mt19937 rnd(time(0));
int n,m,k,x,y,z,A[N];ll f[N];
void Solve(){
	int i,j;ll Ans=1;for(i=1;i<=n;i++) scanf("%d",&A[i]);
	for(i=1;i<=n;i++){
		int x=i-1,Ct=0;
		while(x>=i-A[i]+1) Ct++,x-=A[x];
		if(x<i-A[i]){puts("0");return ;}Ans=Ans*f[Ct]%mod;
	} 
	if(A[n]^n){puts("0");return;}
	printf("%lld\n",Ans);
}
ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
namespace Poly{
	int tr[N];const int g=3,Ig=mpow(g);
	ll C[N],D[N];
	void Init(int n){for(k=1;k<=n;k<<=1);for(int i=0;i<k;i++) tr[i]=(tr[i>>1]>>1)|(i&1?k/2:0),C[i]=D[i]=0;}
	void NTT(ll *A,int k,int op){
		int i,j,h;ll key,now,pus;for(i=0;i<k;i++) if(i<tr[i]) swap(A[i],A[tr[i]]);
		for(i=2;i<=k;i<<=1){
			for(key=mpow(op?g:Ig,(mod-1)/i),j=0;j<k;j+=i){
				for(pus=1,h=j;h<j+i/2;h++) now=pus*A[h+i/2]%mod,A[h+i/2]=(A[h]+mod-now)%mod,A[h]=(A[h]+now)%mod,pus=pus*key%mod;
			}
		}if(op) return;ll In=mpow(k);for(i=0;i<k;i++) A[i]=A[i]*In%mod;
	}
	void Solve(int l,int r){
		if(l==r) {f[l]=(f[l]+f[l-1]*(l-1))%mod;return;}int m=l+r>>1,i;Solve(l,m);
		if(l==2){
			Init(r-l+1+m-l+1);
			for(i=2;i<=m;i++) C[i]=f[i]*(i-1)%mod;for(i=l;i<=m;i++) D[i-l]=f[i];
			NTT(C,k,1);NTT(D,k,1);for(i=0;i<k;i++) C[i]=C[i]*D[i]%mod;NTT(C,k,0);for(i=m+1;i<=r;i++) f[i]=(f[i]+C[i-l])%mod;
		}else{
			Init(r-l+1+m-l+1);
			for(i=2;i<=r-l;i++) C[i]=f[i];for(i=l;i<=m;i++) D[i-l]=f[i];
			NTT(C,k,1);NTT(D,k,1);for(i=0;i<k;i++) C[i]=C[i]*D[i]%mod;NTT(C,k,0);for(i=m+1;i<=r;i++) f[i]=(f[i]+C[i-l]*(i-2))%mod;
		}
		Solve(m+1,r);
	}
}
int main(){
	freopen("1.in","r",stdin);
	int t,i,j;scanf("%d%d",&t,&n);f[0]=1;f[1]=2;if(n>1) Poly::Solve(2,n);
/*	for(i=2;i<=n;i++) {
		f[i]=f[i-1]*(i-1)%mod;
		for(j=2;j<i-1;j++) f[i]=(f[j]*f[i-j]%mod*(j-1)+f[i])%mod;
	}*/
	while(t--) Solve();
} 

标签:P4566,int,luogu,long,CTSC2018,连续,区间,using,define
From: https://www.cnblogs.com/275307894a/p/17214995.html

相关文章

  • luogu「P4313」文理分科 解题报告
    题目描述文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过)小P所在的班级要进行文理分科。他的班级可以用一个\(n\timesm\)的矩阵进行描述,每个格子......
  • luogu P8341 [AHOI2022] 回忆
    题面传送门恭喜你发现一只写挂了却质疑自己贪心错了的纯纯sb。首先一个简单的猜想就是维护每个子树内向上的路径,如果两个子树之间路径可以合并就合并。但是这是有问题的......
  • luogu P8367 [LNOI2022] 盒
    题面传送门比较厉害的题目。首先我们发现我们只需要计算\(i\)和\(i+1\)之间经过的货物数,也即设\(a\)的前缀和为\(Sum\),\(b\)的前缀和为\(c\),则\(i\toi+1\)......
  • luogu P8294 [省选联考 2022] 最大权独立集问题
    题面传送门做了半个下午,写了大半个晚上,真的是dirtywork。首先一个点只会和父亲交换一次,并且交换了两边就相对独立了。因此我们考虑从这个方面入手dp。设\(f_{i,x,y}......
  • Luogu3731 新型城市化 - 二分图 - 网络流 - 强连通分量 -
    题目链接:https://www.luogu.com.cn/problem/P3731题解:考虑原图的补图,因为题目中保证了城市群最多有两个,因此补图是一个二分图,城市群等价于独立集原题转化成了,删去一条边......
  • luogu P6276 [USACO20OPEN]Exercise P
    题面传送门首先考虑一个固定排列的答案是什么。考虑它的若干置换环,应该是所有环环长的LCM,所有数都会转回本来的位置。现在变成计算所有环的环长的LCM的积的问题。注意......
  • 【luogu CF1098D】Eels(结论)
    Eels题目链接:luoguCF1098D题目大意有一个可重集,每次操作会放进去一个数或者取出一个数。然后每次操作完之后,问你对这个集合进行操作,每次选出两个数a,b加起来合并回......
  • luogu P8444 不等价交换法则
    题目传送门分析仔细审了题面,猜想是贪心模拟,下面给出证明:因为只能用元买一个商品,所以要挑贵的买(越贵,换得的商品越多),后令商品尽可能的去换低价格的商品,即把手头所有的商品......
  • [luogu P4705玩游戏] 题解
    P4705玩游戏题解题意概括给出两个序列\(a_0,a_2,\cdotsa_{n-1}\),\(b_0,b_2,\cdotsb_{m-1}\),从两个序列中各等概率的选出两个数\(a_i,b_j\),对于\(k\in[1,t]\)......
  • Solution Luogu6097 子集卷积
    其实是暴力。因为这是模板题,所以模板的前置知识也要讲。前置知识:FWT计算或卷积。这里只需要掌握快速计算或卷积的方法,所以内容较少。如果向了解更多(比如异或卷积)的话......