正题

题目链接:https://loj.ac/p/6503


题目大意

\(n\)张卡\(m\)种,第\(i\)种卡有\(a_i\)张,求所有排列中有\(k\)对相邻且相同的卡牌。

\(1\leq n\leq 10^5,0\leq k\leq 10^5,1\leq m\leq 20000,\sum_{i=1}^ma_i=n\)


解题思路

\(k\)对相邻的相同,就是可以分成有\(n-k\)组相同的。

考虑这个问题,把每组牌分成若干组插到不同位置,先不考虑这样可能插到相邻位置的情况我们后面可以再用容斥消掉。

那么对于一个\(a\),分成\(i\)组的方案就是\(\binom{a-1}{i-1}\),因为排列,列出生成函数\(\sum_{i=1}^a\binom{a-1}{i-1}\frac{x^i}{i!}\)。

然后用分治\(NTT\)乘起来,最后第\(i\)项乘上一个\(i!\)就是方案了。

然后考虑容斥,枚举一个\(i\leq n-k\)然后相当于至少有\(k\)对相邻,现在要减去更多的,所以容斥系数就是\((-1)^{n-k-i}\binom{n-i}{k}\)

时间复杂度\(O(n\log n\log m)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2e5+10,T=19,P=998244353;
struct Poly{
ll a[N<<2],n;
}F[T+1];bool v[T+1];
ll m,n,k,w[N],inv[N],fac[N],r[N],x[N],y[N];
ll power(ll x,ll b){
ll ans=1;
while(b){
if(b&1)ans=ans*x%P;
x=x*x%P;b>>=1;
}
return ans;
}
void NTT(ll *f,ll n,ll op){
for(ll i=0;i<n;i++)
if(i<r[i])swap(f[i],f[r[i]]);
for(ll p=2;p<=n;p<<=1){
ll len=p>>1,tmp=power(3,(P-1)/p);
if(op==-1)tmp=power(tmp,P-2);
for(ll k=0;k<n;k+=p){
ll buf=1;
for(ll i=k;i<k+len;i++){
ll tt=buf*f[i+len]%P;
f[i+len]=(f[i]-tt+P)%P;
f[i]=(f[i]+tt)%P;
buf=buf*tmp%P;
}
}
}
if(op==-1){
ll invn=power(n,P-2);
for(ll i=0;i<n;i++)
f[i]=f[i]*invn%P;
}
return;
}
void Mul(Poly &F,Poly &G){
ll n=1;
while(n<F.n+G.n-1)n<<=1;
for(ll i=0;i<F.n;i++)x[i]=F.a[i];
for(ll i=0;i<G.n;i++)y[i]=G.a[i];
for(ll i=F.n;i<n;i++)x[i]=0;
for(ll i=G.n;i<n;i++)y[i]=0;
for(ll i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)?(n>>1):0);
NTT(x,n,1);NTT(y,n,1);
for(ll i=0;i<n;i++)x[i]=x[i]*y[i]%P;
NTT(x,n,-1);
for(ll i=0;i<n;i++)F.a[i]=x[i];
F.n=F.n+G.n-1;return;
}
ll FindA(){
for(ll i=0;i<T;i++)
if(!v[i]){v[i]=1;return i;}
}
ll C(ll n,ll m)
{return fac[n]*inv[m]%P*inv[n-m]%P;}
ll NTT(ll l,ll r){
if(l==r){
ll x=FindA();
for(ll i=1;i<=w[l];i++)
F[x].a[i]=inv[i]*C(w[l]-1,i-1)%P;
F[x].n=w[l]+1;return x;
}
ll mid=(l+r)>>1;
ll ls=NTT(l,mid),rs=NTT(mid+1,r);
Mul(F[ls],F[rs]);v[rs]=0;return ls;
}
signed main()
{
scanf("%lld%lld%lld",&m,&n,&k);inv[1]=1;
for(ll i=2;i<N;i++)inv[i]=P-inv[P%i]*(P/i)%P;
fac[0]=inv[0]=1;
for(ll i=1;i<N;i++)fac[i]=fac[i-1]*i%P,inv[i]=inv[i-1]*inv[i]%P;
for(ll i=1;i<=m;i++)scanf("%lld",&w[i]);
ll p=NTT(1,m),ans=0;
for(ll i=n-k,f=1;i>=m;i--,f=-f)
ans=(ans+f*F[p].a[i]*fac[i]%P*C(n-i,k)%P)%P;
printf("%lld\n",(ans+P)%P);
return 0;
}

Loj#6503-「雅礼集训 2018 Day4」Magic【分治NTT】的更多相关文章

  1. Loj #6503. 「雅礼集训 2018 Day4」Magic

    Loj #6503. 「雅礼集训 2018 Day4」Magic 题目描述 前进!前进!不择手段地前进!--托马斯 · 维德 魔法纪元元年. 1453 年 5 月 3 日 16 时,高维碎片接触地球. ...

  2. LOJ#6503.「雅礼集训 2018 Day4」Magic[容斥+NTT+启发式合并]

    题意 \(n\) 张卡牌 \(m\) 种颜色,询问有多少种本质不同的序列满足相邻颜色相同的位置数量等于 \(k\). 分析 首先本质不同不好直接处理,可以将同种颜色的卡牌看作是不相同的,求出答案后除以 ...

  3. 【loj#6503.】「雅礼集训 2018 Day4」Magic(生成函数+容斥)

    题面 传送门 题解 复杂度比较迷啊-- 以下以\(n\)表示颜色总数,\(m\)表示总的卡牌数 严格\(k\)对比较难算,我们考虑容斥 首先有\(i\)对就代表整个序列被分成了\(m-i\)块互不相同 ...

  4. LOJ6503. 「雅礼集训 2018 Day4」Magic(容斥原理+NTT)

    题目链接 https://loj.ac/problem/6503 题解 题中要求本质不同的序列数量,不太好搞.我们考虑给相同颜色的牌加上编号,这样所有牌都不相同.那么如果我们求出了答案,只需要将答案除 ...

  5. 2018.10.27 loj#6035. 「雅礼集训 2017 Day4」洗衣服(贪心+堆)

    传送门 显然的贪心题啊...考试没调出来10pts滚了妙的一啊 直接分别用堆贪心出洗完第iii件衣服需要的最少时间和晾完第iii件衣服需要的最少时间. 我们设第一个算出来的数组是aaa,第二个是bbb ...

  6. LOJ #6509. 「雅礼集训 2018 Day7」C

    神仙题 LOJ #6509 题意 给定一棵树,点权为0/1,每次随机一个点(可能和之前所在点相同)走到该点并将其点权异或上1 求期望的移动距离使得所有点点权相同 题解 根本不会解方程 容易发现如果一个 ...

  7. loj 6037 「雅礼集训 2017 Day4」猜数列 - 动态规划

    题目传送门 传送门 题目大意 有一个位置数列,给定$n$条线索,每条线索从某一个位置开始,一直向左或者向右走,每遇到一个还没有在线索中出现的数就将它加入线索,问最小的可能的数列长度. 依次从左到右考虑 ...

  8. Loj 6036 「雅礼集训 2017 Day4」编码 - 2-sat

    题目传送门 唯一的传送门 题目大意 给定$n$个串,每个串只包含 ' .问是否可能任意两个不同的串不满足一个是另一个的前缀. 2-sat的是显然的. 枚举每个通配符填0还是1,然后插入Trie树. 对 ...

  9. LOJ #6037.「雅礼集训 2017 Day4」猜数列 状压dp

    这个题的搜索可以打到48分…… #include <cstdio> #include <cstring> #include <algorithm> ; bool m ...

随机推荐

  1. 两款轻量级服务器 Http-server && SimpleHTTPServer

    Http-server # 全局安装 npm install http-server -g # 启动服务 # 禁用缓存 http-server -c-1 # 在当前目录下的www启动服务器 http- ...

  2. 数据结构解析-HashTable

    概要 HashTable也是散列表的一种实现,我们在上一篇解析了HashMap,在这里我们与HashMap做个对比,让你能清晰的了解两者的区别: 散列表 实现方式 数据安全 数据安全实现方式 key\ ...

  3. 【java虚拟机】内存溢出与内存泄漏

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/7354857.html 一.基本概念 内存溢出:简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提 ...

  4. Flink Data transformation(转换)

    Flink Data transformation 算子学习 1.Source:数据源,Flink在流处理和批处理上的source大概有4类: 基于本地集合的source.基于文件的source.基于 ...

  5. Go与接口:实现接口的条件

    接口类型变量 Go是强类型语言,你不能将整数值赋值给浮点型变量.同样,也不能将没有实现接口的类型值赋值给接口类型变量. // 1.定义变量是接口类型 var w io.Writer // 2.将具体类 ...

  6. rabbitMq可靠性投递之配置(消息至交换机,至队列不通的回调)

    @Bean public RabbitTemplate rabbitTemplate(CachingConnectionFactory factory) { //若使用confirm-callback ...

  7. 配置双jdk

    1 CLASSPATH:.%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar 2 JAVA_HOME:%JAVA_HOME ...

  8. Ubuntu中添加desktop entry

    创建desktop文件 gedit my_app.desktop 添加文件内容,在启动时,选择加载的bashrc文件,用于初始化,这样可以用不同的desktop entry启动不同的环境,提高打开环境 ...

  9. MySQL版本浅介

    一.关于MySQL发行版介绍: 1. MySQL官方发行版 MySQL是最流行的数据库,主要特点: 简单:MySQL使用很简单,可以无师自通地参照文档安装运行和使用MySQL,几乎没有什么门槛. 开源 ...

  10. Python - 面向对象编程 - __call__()

    __call()__ 的作用 使得类实例对象可以像普通函数那样被调用 实际栗子 from typing import Callable class PoloBlog: def __init__(sel ...