首页 > 其他分享 >[GDKOI2023]错排

[GDKOI2023]错排

时间:2024-01-31 15:48:23浏览次数:26  
标签:10 return GDKOI2023 int Subtask iv 1LL 错排

[GDKOI2023 提高组] 错排

题目描述

小 X 最近学习了错排问题,于是开始思考一个关于它的变种问题:有多少个长度为 \(n\) 的排列 \(p\),满足对
于 \(i \le m\) 的位置满足 \(p_i > m\),且对于所有位置 \(i\) 都满足 \(p_i \ne i\)?

小 X 一共想出了 \(T\) 个这样的问题,你能告诉他每个问题的答案吗?

由于答案可能过大,你只需要求出答案对 \(998244353\) 取模后的值即可。

输入格式

第一行输入一个整数 \(T\),表示询问组数。

接下来的 \(T\) 行,每行输入两个整数 $ n, m$。

输出格式

输出 \(T\) 行,每行一个整数表示答案对 \(998244353\) 取模后的值。

样例 #1

样例输入 #1

6
8 0
8 4
100 10
1000 100
10000 1000
100000 10000

样例输出 #1

14833
576
548326276
694205000
493811811
135068319

提示

对于 100% 的数据,\(0 ≤ T ≤ 2 \times 10^5\),\(0 ≤ m ≤ n ≤ 2 \times 10^5\)。

本题采用子任务捆绑测试。

  • Subtask 1 (1pts):保证 \(T = 0\)。
  • Subtask 2 (9pts):保证 \(T ≤ 10\),\(n, m ≤ 8\)。
  • Subtask 3 (10pts):保证 \(m = 0\)。
  • Subtask 4 (20pts):保证 \(n, m ≤ 5000\)。
  • Subtask 5 (20pts):保证 \(T ≤ 10\)。
  • Subtask 6 (40pts):无特殊性质。

这题好像有很厉害的 \(O((n+m)\sqrt n)\) 甚至 \(O(nlog^2n)\) 做法,但是我不会。
首先 \(2m>n\) 显然无解。

设 \(f_(i,j)\) 表示有 \(i\) 个位置,但是有 \(j\) 个位置钦定不一定要错开排的,\(i-j\) 个位置一定要错开的方案数,\(g_i\) 为 \(i\) 个数的错排数。

最后答案就是 \(\frac{(n-m)!}{(n-2m)!}\times f(n-m,m)\)

考虑如何计算 \(f(i,j)\)。枚举有多少个数实际上是错排的,

\[f(i,j)=\sum\limits_{i=0}^{m}g_i\binom{m}{i} \]

将其写作 \([x^{n-m}]g\times(x+1)^m\),分块处理。用卷积预处理出 \(g_i\times(x+1)^{jB}\) 的式子,查询时再乘上剩下的。复杂度是 \(O(qB+\frac nBlogn)\),B 取 \(\sqrt{nlog n}\) 的时候,复杂度 \(O(n\sqrt{nlog n})\)

#include<bits/stdc++.h>
using namespace std;
const int P=998244353,g=3,ivg=(P+1)/g,N=262144,B=3000;
int f[N],TME,r[N],dp[N],n,m,pw[100][N],pf[N],iv[N],inv[N],ans,C[B][B];
int pown(int x,int y)
{
	if(!y)
		return 1;
	int t=pown(x,y>>1);
	if(y&1)
		return 1LL*t*t%P*x%P;
	return 1LL*t*t%P;
}
const int ivN=pown(N,P-2);
void ntt(int a[],int op)
{
	for(int i=0;i<N;i++)
		if(r[i]<i)
			swap(a[i],a[r[i]]);
	for(int md=1;md<N;md<<=1)
	{
		int p=pown(op? g:ivg,(P-1)/(md<<1));
		for(int i=0;i<N;i+=md<<1)
		{
			for(int j=0,pw=1;j<md;j++,pw=1LL*pw*p%P)
			{
				int x=a[i+j+md]*1LL*pw%P;
				a[i+j+md]=(a[i+j]-x+P)%P;
				(a[i+j]+=x)%=P;
			}
		}
	}
	if(!op)
		for(int i=0;i<N;i++)
			a[i]=1LL*a[i]*ivN%P;
}
inline int read()
{
	int s=0;
	char ch=getchar();
	while(ch>'9'||ch<'0')
		ch=getchar();
	while(ch<='9'&&ch>='0')
		s=s*10+ch-'0',ch=getchar();
	return s;
}
int CC(int n,int m)
{
	return 1LL*f[n]*iv[m]%P*iv[n-m]%P; 
}
int main()
{
	//freopen("P10103_21.in","r",stdin);
//	freopen("a.out","w",stdout);
	for(int i=iv[0]=f[0]=inv[1]=1;i<N;i++)
	{
		r[i]=(r[i>>1]>>1)|(i&1)*N/2;
		f[i]=1LL*f[i-1]*i%P;
		if(i^1)
		{
			dp[i]=(dp[i-1]*1LL*i+(i&1? -1:1))%P;
			inv[i]=(P-P/i)*1LL*inv[P%i]%P;
		}
		iv[i]=iv[i-1]*1LL*inv[i]%P;
	}
	dp[0]=1;
	for(int i=0;i<B;i++)
		for(int j=0;j<=i;j++)
			C[i][j]=CC(i,j);
//	printf("%d\n",C(0,0));
	pf[0]=pf[1]=1;
	ntt(dp,1);
	memcpy(pw[0],dp,sizeof(dp)); 
	ntt(pf,1);
	for(int i=0;i<N;i++)
		pf[i]=pown(pf[i],B);
	for(int i=1;i*B<N;i++)
		for(int j=0;j<N;j++)
			pw[i][j]=pw[i-1][j]*1LL*pf[j]%P;
	for(int i=0;i*B<N;i++)
		ntt(pw[i],0);
	scanf("%d",&TME);
	while(TME--)
	{
		n=read(),m=read(),ans=0;
		if(2*m>n)
		{
			puts("0");
			continue;
		}
		int x=m%B;
		for(int j=0;j<=x&&j<=n-m;j++)
			(ans+=1LL*pw[m/B][n-m-j]*C[x][j]%P)%=P;
		printf("%lld\n",1LL*ans*f[n-m]%P*iv[n-2*m]%P);
	}
	return 0;
}

标签:10,return,GDKOI2023,int,Subtask,iv,1LL,错排
From: https://www.cnblogs.com/mekoszc/p/17999380

相关文章

  • 小景的Dba之路--impdp导入数据问题报错排查总结
    小景最近在工作中遇到了一个问题,用impdp做数据导入的时候,有以下报错,下面是问题排查过程:首先看到了ORA-01950:noprivilegesontablespace‘PUBDATA’这个报错,小景想到了以下原因:权限问题:ORA-01950错误表示用户没有在PUBDATA表空间上的特定对象的权限。这可能是由于数据库权......
  • 圆排列、错排列例题
    本篇最初的产生原因是因为他们本身没有模板题,而练习他们的渠道少之又少,故进行一些查找和整理。(有新发现随时更新……)错排列P1595信封问题(普及-)就是个纯板子P3182[HAOI2016]放棋子(提高+/省选-)考场上遇到这道题可能会迟疑,但本身也是纯纯板子(看题解貌似要高精度?)圆排列等......
  • kubenetes 报错排查
    1.报code=Unknowndesc=failedtogetsandboxip:checknetworknamespaceclosed:removenetns:unlinkat/var/run/netns/cni-2502ee8a-9f06-2a44-66c6-59e2a7a277f9:deviceorresourcebusy解决方案:seecode=Unknowndesc=failedtogetsandboxip:chec......
  • 2023-9-20交易日志报错排查分析
    1、下单失败:名词解释:NOTIONAL名义价值来源:https://binance-docs.github.io/apidocs/spot/cn/#cc81fff589名义价值过滤器(NOTIONAL)定义了订单在一个交易对上可以下单的名义价值区间.applyMinToMarket定义了minNotional是否适用于市价单(MARKET)applyMaxToMarket定义了......
  • 【DSY 4484】矩阵 题解(带限错排)
    DSY传送门。(带限制)错排问题。神仙题。Solution根据题目的问法,发现我们只想统计比给定矩阵\(A\)小的矩阵,记这个矩阵为\(B\)。显然,\(B\)的第\(i\)行一定从某个位置开始小于\(A\)的第\(i\)行,且前面的内容和\(A\)都是一样的。所以我们只需要枚举这个“开始变小”......
  • hdu2068 RPG的错排(错排)
    思路:我们定义f(n)为n个人抽到的情况总数。对于第n个人,他要不抽中自己,即要抽中其他n-1个人,有n-1种可能,接下来讨论下,如果第n个人它抽中的人也抽中了第n个人,那么有f(n-2)种情况,如果第n个人抽中的人没有抽中第n个人,那么有f(n-1)可能,所以f(n)=(n-1)*(f(n-1)+f(n-2))。      ......
  • GDKOI2023提高
    稍后将会带来详细题解。A矩阵随机一个向量乘到两边即可,错误率\(\dfrac{1}{998244353}\)。B错排组合意义\(f_{i,j}\)代表\(i\)个数没有限制,共有\(j\)个数求错排数。则\(ans=P_{n-m}^{m}f_{m,n-m}\)。不妨设没有限制得数为前\(i\)个数,后面\(j-i\)个数有限制,枚举......
  • 【ACM组合数学 | 错排公式】写信
    题目链接:https://ac.nowcoder.com/acm/contest/54484/B题意很简单,但是数据范围偏大。错排公式首先来推导一下错排公式:$$D(n)=n!\sum_{k=0}^{n}\frac{(-1)^k}{k!}$$设一个函数:$$S_i表示一个排列中p_i=i的方案数$$那么我们可以知道:$$D(n)=n!-|\cup_{i=1}^{n}S_i|$$......
  • 【ACM组合数学 | 错排公式】写信
    题目链接:https://ac.nowcoder.com/acm/contest/54484/B题意很简单,但是数据范围偏大。错排公式首先来推导一下错排公式:\[D(n)=n!\sum_{k=0}^{n}\frac{(-1)^k}{k!}\]设一个函数:\[S_i表示一个排列中p_i=i的方案数\]那么我们可以知道:\[D(n)=n!-|\cup_{i=1}^{n}S_i|\]......
  • s2oj2046 GDKOI2023 Day1T3 异或图
    s2oj2046GDKOI2023Day1T3异或图好题,与Ex-DistinctMultiples类似,题解。首先考虑没有边的情况,那么我们需要满足条件\(1,3\)。考虑从高位开始计算,设当前考虑到第......