题解-CTS2019 珍珠
题面
有 \(n\) 个在 \([1,d]\) 内的整数,求使可以拿出 \(2m\) 个整数凑成 \(m\) 个相等的整数对的方案数。
数据范围:\(0\le m\le 10^9\),\(1\le n\le 10^9\),\(1\le d\le 10^5\)。
蒟蒻语
非常巧妙的题,主要要用到二项式反演、指数级生成函数和 NTT。
做个广告,这是我读过最好的生成函数讲解:link。
蒟蒻解
设 \(c_i\) 表示 \(i\) 这个数的出现次数。
设 \(odd=\sum [c_i\in {\rm odd} ]\),即 \(c_i\) 奇数个数。
很明显最多能凑成 \(\frac{n-odd}{2}\) 对,按题意:
\frac{n-odd}{2}&\ge m\\
odd&\le n-2m
\end{aligned}
\]
这里有两个特判,如果 \(n-2m<0\) 答案是 \(0\),如果 \(n-2m\ge d\) 答案是 \(d^n\)。
设 \(g(i)\) 表示 \(odd=i\) 的方案数。
设 \(f(i)\) 表示钦定 \(i\) 个 \(c_i\) 是奇数,剩下随意的方案数(不是 \(odd\ge i\) 的方案数,这里对一些排列会重复统计,但是反演完就没事了)。
\]
所以可以先求 \(f(i)\),用到了指数级生成函数,中间把每个 \(e\) 的幂次项展开,最后归成卷积形式:
f(i)=&{d \choose i} \left(\frac{e^x-e^{-x}}{2}\right)^i e^{(d-i)x} n![n]\\
=&{d \choose i} (e^x-e^{-x})^i e^{(d-i)x} \frac{n!}{2^i}[n]\\
=&{d \choose i} e^{(d-i)x} \sum_{j=0}^i(-1)^{i-j} {i\choose j}e^{(j-(i-j))x} \frac{n!}{2^i}[n]\\
=&{d \choose i} e^{(d-i)x} \sum_{j=0}^i(-1)^{i-j} {i\choose j}e^{(2j-i)x} \frac{n!}{2^i}[n]\\
=&{d \choose i} \frac{n!}{2^i}\sum_{j=0}^i(-1)^{j} {i\choose j}e^{(d-2j)x} [n]\\
=&{d \choose i} \frac{n!}{2^i}\sum_{j=0}^i(-1)^{j} {i\choose j} \frac{(d-2j)^n}{n!}\\
=&\frac{d!}{i!(d-i)!2^i}\sum_{j=0}^i(-1)^{j} \frac{i!}{j!(i-j)!} (d-2j)^n\\
=&\frac{d!}{(d-i)!2^i}\sum_{j=0}^i\frac{(-1)^{j}(d-2j)^n}{j!}\cdot \frac{1}{(i-j)!} \\
\end{aligned}
\]
最后一个难点是如何求:
\]
感觉可以凑成卷积形式,但总差一点。尝试把 \(f\) 和 \(g\) 都反过来,即令 \(f'(x)=f(d-x)\),\(g'(x)=g(d-x)\):
g(i)=&\sum_{x=i}^d(-1)^{x-i}{x\choose i} f(x)\\
=&\sum_{x=i}^d(-1)^{x-i}{x\choose i} f'(d-x)\\
=&\sum_{x=0}^{d-i}(-1)^{d-x-i}{d-x\choose i} f'(x)\\
\end{aligned}\\
g'(d-i)=\sum_{x=0}^{d-i}(-1)^{d-x-i}{d-x\choose i} f'(x)\\
\begin{aligned}
g'(i)=&\sum_{x=0}^{i}(-1)^{i-x}{d-x\choose d-i} f'(x)\\
=&\sum_{x=0}^{i}(-1)^{i-x}\frac{(d-x)!}{(d-i)!(i-x)!} f'(x)\\
=&\frac{1}{(d-i)!}\sum_{x=0}^{i} (-1)^{i-x}\frac{1}{(i-x)!}\cdot f'(x)(d-x)!\\
\end{aligned}\\
\]
然后就可以求 \(g(i)\) 了。
答案便是 \(\sum_{i=0}^{n-2m} g(i)\)。
代码
#include <bits/stdc++.h>
using namespace std;
//Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair((a),(b))
#define x first
#define y second
#define bg begin()
#define ed end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
#define R(i,a,b) for(int i=(a),i##E=(b);i<i##E;i++)
#define L(i,a,b) for(int i=(b)-1,i##E=(a)-1;i>i##E;i--)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f;
//Data
const int N=1e5;
int n,m,d,ans;
//Math
const int mod=998244353;
int Pow(int a,int x){
int res=1; for(;x;x>>=1,a=1ll*a*a%mod)
if(x&1) res=1ll*res*a%mod; return res;
}
const int mN=N+1;
int fac[mN],ifac[mN];
void math_init(){
fac[0]=1;R(i,1,d+1) fac[i]=1ll*fac[i-1]*i%mod;
ifac[d]=Pow(fac[d],mod-2);
L(i,0,d) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
}
//Poly
const int pN=mN<<2;
int f[pN],g[pN];
const int G=3,iG=Pow(3,mod-2);
int rev[pN],pn;
void poly_init(){
pn=1<<int(ceil(log2(d*2+2)));
R(i,0,pn) rev[i]=(rev[i>>1]>>1)|((i&1)*(pn>>1));
}
void NTT(int* a,int t){
R(i,0,pn)if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int mid=1;mid<pn;mid<<=1){
int wn=Pow(~t?G:iG,(mod-1)/(mid<<1));
for(int i=0;i<pn;i+=(mid<<1)){
int w=1;
R(j,i,mid+i){
int x=a[j],y=1ll*a[mid+j]*w%mod;
a[j]=(x+y)%mod,a[mid+j]=(x-y+mod)%mod,w=1ll*w*wn%mod;
}
}
}
if(!~t){
int in=Pow(pn,mod-2);
R(i,0,pn) a[i]=1ll*a[i]*in%mod;
}
}
//Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>d>>n>>m;
if(n-2*m<0) return cout<<0<<'\n',0;
if(d<=n-2*m) return cout<<Pow(d,n)<<'\n',0;
math_init(),poly_init();
R(i,0,d+1){
f[i]=1ll*Pow((d-2*i+mod)%mod,n)*ifac[i]%mod;
if(i&1) f[i]=(mod-f[i])%mod;
g[i]=ifac[i];
}
R(i,d+1,pn) f[i]=g[i]=0;
NTT(f,1),NTT(g,1);
R(i,0,pn) f[i]=1ll*f[i]*g[i]%mod;
NTT(f,-1);
R(i,d+1,pn) f[i]=g[i]=0;
R(i,0,d+1) f[i]=1ll*f[i]*fac[d]%mod*ifac[d-i]%mod*Pow(2,mod-1-i)%mod;
reverse(f,f+d+1);
R(i,0,d+1) f[i]=1ll*f[i]*fac[d-i]%mod;
R(i,0,d+1){
g[i]=ifac[i];
if(i&1) g[i]=(mod-g[i])%mod;
}
R(i,d+1,pn) f[i]=g[i]=0;
NTT(f,1),NTT(g,1);
R(i,0,pn) g[i]=1ll*f[i]*g[i]%mod;
NTT(g,-1);
R(i,d+1,pn) f[i]=g[i]=0;
R(i,0,d+1) g[i]=1ll*g[i]*ifac[d-i]%mod;
reverse(g,g+d+1);
R(i,0,n-2*m+1) (ans+=g[i])%=mod;
cout<<ans<<'\n';
return 0;
}
祝大家学习愉快!
题解-CTS2019 珍珠的更多相关文章
- 【题解】CTS2019珍珠(二项式反演+卷积)
[题解]CTS2019珍珠 题目就是要满足这样一个条件\(c_i\)代表出现次数 \[ \sum {[\dfrac {c_i } 2]} \ge 2m \] 显然\(\sum c_i=n\)所以,而且 ...
- [CTS2019]珍珠——二项式反演
[CTS2019]珍珠 考虑实际上,统计多少种染色方案,使得出现次数为奇数的颜色数<=n-2*m 其实看起来很像生成函数了 n很大?感觉生成函数会比较整齐,考虑生成函数能否把n放到数值的位置,而 ...
- 题解 P5401 [CTS2019]珍珠
蒟蒻语 这题太玄学了,蒟蒻写篇题解来让之后复习 = = 蒟蒻解 假设第 \(i\) 个颜色有 \(cnt_i\) 个珍珠. \(\sum\limits_{i=1}^{n} \left\lfloor\f ...
- Luogu5401 CTS2019珍珠(生成函数+容斥原理+NTT)
显然相当于求有不超过n-2m种颜色出现奇数次的方案数.由于相当于是对各种颜色选定出现次数后有序排列,可以考虑EGF. 容易构造出EGF(ex-e-x)/2=Σx2k+1/(2k+1)!,即表示该颜色只 ...
- LOJ3120 CTS2019 珍珠 生成函数、二项式反演、NTT
传送门 题目大意:给出一个长度为\(n\)的序列\(a_i\),序列中每一个数可以取\(1\)到\(D\)中的所有数.问共有多少个序列满足:设\(p_i\)表示第\(i\)个数在序列中出现的次数,\( ...
- [LOJ#3120][Luogu5401][CTS2019]珍珠(容斥+生成函数)
https://www.luogu.org/blog/user50971/solution-p5401 #include<cstdio> #include<algorithm> ...
- 题解-CTS2019氪金手游
Problem \(\mathtt {loj-3124}\) 题意概要:给定 \(n\) 个点,\(w_i\) 分别有 \(p_{i,1},p_{i,2},p_{i,3}\) 的概率取 \(1,2,3 ...
- 题解-CTS2019随机立方体
problem \(\mathtt {loj-3119}\) 题意概要:一个 \(n\times m\times l\) 的立方体,立方体中每个格子上都有一个数,如果某个格子上的数比三维坐标中至少有一 ...
- [CTS2019]珍珠(NTT+生成函数+组合计数+容斥)
这题72分做法挺显然的(也是我VP的分): 对于n,D<=5000的数据,可以记录f[i][j]表示到第i次随机有j个数字未匹配的方案,直接O(nD)的DP转移即可. 对于D<=300的数 ...
随机推荐
- 邻居子系统1.5 neigh output
1.5.1 当邻居项不处于NUD_CONNECTD状态时,不允许快速路径发送报文,函数neigh_resolve_output 用于慢而安全的输出,通常用初始化neigh_ops结构 来实例outpu ...
- binary hacks读数笔记(readelf基本命令)
一.首先对readelf常用的参数进行简单说明: readelf命令是Linux下的分析ELF文件的命令,这个命令在分析ELF文件格式时非常有用,下面以ELF格式可执行文件test为例详细介绍: 1. ...
- Centos7升级内核后无法启动解决办法
前言 这个问题存在有一段时间了,之前做的centos7的ISO,在进行内核的升级以后就存在这个问题: 系统盘在板载sata口上是可以正常启动新内核并且能识别面板硬盘 系统盘插在面板口上新内核无法启动, ...
- 《.NET 5.0 背锅案》第7集-大结局:捉拿真凶 StackExchange.Redis.Extensions 归案
第1集:验证 .NET 5.0 正式版 docker 镜像问题 第2集:码中的小窟窿,背后的大坑,发现重要嫌犯 EnyimMemcachedCore 第3集-剧情反转:EnyimMemcachedCo ...
- C++运行时类型判断dynamic_cast和typeid
dynamic_cast dynamic_cast < Type-id > ( expression ) dynamic_cast<类型>(变量) 在运行期间检测类型转换是否安 ...
- vue路由懒加载方式
方式一:结合Vue的异步组件和Webpack的代码分析 const Home = resole => {require.ensure(['../components/Home.vue'],() ...
- jwt鉴权学习 (php示例代码)
前段时间听朋友讲起 jwt鉴权,博主我是一脸懵逼,通过朋友坚持不懈的讲解,我终于听懂了,jwt就是登陆token校验嘛 然而事情并不是博主想象的那么简单,在一个艳阳高照,晴空万里的夜晚,博主手贱百度了 ...
- iOS图文混排的几种方式
最近优化升级了之前做的一个项目,现在这一期已接近尾声了,今天可以腾出些时间总结一下最近项目中用的比较多的图片文字混排显示的内容.现在遇到比较多的图文混排的基本有三种:一种是在标签中显示 价格符号+价格 ...
- Java基础教程——多线程:创建线程
多线程 进程 每一个应用程序在运行时,都会产生至少一个进程(process). 进程是操作系统进行"资源分配和调度"的独立单位. Windows系统的"任务管理器&quo ...
- String.Split()函数 非原创
我们在上次学习到了 String.Join函数(http://blog.csdn.net/zhvsby/archive/2008/11/28/3404704.aspx),其中用到了String.SPl ...