题目

桌面上摆放着 \(m\) 种魔术卡,共 \(n\) 张,第 \(i\) 种魔术卡数量为 \(a_i\),魔术卡顺次摆放,形成一个长度为 \(n\) 的魔术序列,

在魔术序列中,若两张相邻魔术卡的种类相同,则它们被称为一个魔术对。

两个魔术序列本质不同,当且仅当存在至少一个位置,使得两个魔术序列这个位置上的魔术卡的种类不同,

求本质不同的恰好包含 \(k\) 个魔术对的魔术序列的数量,答案对 \(998244353\) 取模。


分析

考虑给种类相同的也存在次序,最后再除以\(a_i!\),

对于单个种类至少有\(k\)个魔术对的方案就是

\[C(a_i,k)\frac{(a_i-1)!}{(a_i-k-1)!}
\]

就是先选择\(k\)个成为魔术对,再一个一个插入,

由于剩下的\(n-2*k\)个不确定是否产生魔术对,所以是至少

上面这个式子直接表示成\(m\)个多项式,用分治NTT

那恰好就不好做了,考虑容斥,

\[ans=\sum_{i=k}^n(-1)^{i-k}C(i,k)f[i](n-i)!
\]

\((n-i)!\)是因为把剩下的任意排


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <algorithm>
#define rr register
#define mem(f,n) memset(f,0,sizeof(int)*(n))
#define cpy(f,g,n) memcpy(f,g,sizeof(int)*(n))
using namespace std;
const int mod=998244353,inv3=332748118,N=100011;
typedef long long lll; typedef unsigned long long ull;
int n,m,Gmi[31],Imi[31],len[15],fac[N],inv[N],ff[15][N<<2],a[N],v[15],t=1,ans,k;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed address(){
for (rr int i=0;i<15;++i)
if (!v[i]) return i;
return -1;
}
inline signed ksm(int x,int y){
rr int ans=1;
for (;y;y>>=1,x=1ll*x*x%mod)
if (y&1) ans=1ll*ans*x%mod;
return ans;
}
inline signed C(int n,int m){return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;}
namespace Theoretic{
int rev[N<<2],LAST; ull Wt[N<<2],F[N<<2];
inline void Pro(int n){
if (LAST==n) return; LAST=n,Wt[0]=1;
for (rr int i=0;i<n;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)?n>>1:0);
}
inline void NTT(int *f,int n,int op){
Pro(n);
for (rr int i=0;i<n;++i) F[i]=f[rev[i]];
for (rr int o=1,len=1;len<n;++o,len<<=1){
rr int W=(op==1)?Gmi[o]:Imi[o];
for (rr int j=1;j<len;++j) Wt[j]=Wt[j-1]*W%mod;
for (rr int i=0;i<n;i+=len+len)
for (rr int j=0;j<len;++j){
rr int t=Wt[j]*F[i|j|len]%mod;
F[i|j|len]=F[i|j]+mod-t,F[i|j]+=t;
}
if (o==10) for (rr int j=0;j<n;++j) F[j]%=mod;
}
if (op==-1){
rr int invn=ksm(n,mod-2);
for (rr int i=0;i<n;++i) F[i]=F[i]%mod*invn%mod;
}else for (rr int i=0;i<n;++i) F[i]%=mod;
for (rr int i=0;i<n;++i) f[i]=F[i];
}
inline void Cb(int *f,int *g,int n){
for (rr int i=0;i<n;++i) f[i]=1ll*f[i]*g[i]%mod;
}
inline signed CDQ_NTT(int l,int r){
if (l==r){
rr int now=address();
len[now]=a[l],v[now]=1;
for (rr int i=0;i<len[now];++i)
ff[now][i]=1ll*C(a[l],i)*C(a[l]-1,i)%mod*fac[i]%mod;
return now;
}
rr int mid=(l+r)>>1,L;
rr int lef=CDQ_NTT(l,mid),rig=CDQ_NTT(mid+1,r);
for (L=1;L<len[lef]+len[rig];L<<=1);
NTT(ff[lef],L,1),NTT(ff[rig],L,1),Cb(ff[lef],ff[rig],L),
mem(ff[rig],L),len[lef]+=len[rig],len[rig]=v[rig]=0,NTT(ff[lef],L,-1);
return lef;
}
}
inline void GmiImi(){
for (rr int i=0;i<31;++i) Gmi[i]=ksm(3,(mod-1)/(1<<i));
for (rr int i=0;i<31;++i) Imi[i]=ksm(inv3,(mod-1)/(1<<i));
}
signed main(){
m=iut(),n=iut(),k=iut(),GmiImi(),inv[0]=inv[1]=fac[0]=fac[1]=1;
for (rr int i=2;i<=n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for (rr int i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i]*inv[i-1]%mod;
for (rr int i=1;i<=m;++i) a[i]=iut(),t=1ll*t*inv[a[i]]%mod;
rr int now=Theoretic::CDQ_NTT(1,m);
for (rr int i=k;i<=n;++i)
if ((i-k)&1) ans=(ans+mod-1ll*ff[now][i]*C(i,k)%mod*fac[n-i]%mod)%mod;
else ans=(ans+1ll*ff[now][i]*C(i,k)%mod*fac[n-i]%mod)%mod;
return !printf("%lld",1ll*ans*t%mod);
}

#分治NTT,容斥定理,排列组合#LOJ 6503 「雅礼集训 2018 Day4」Magic的更多相关文章

  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. Loj#6503-「雅礼集训 2018 Day4」Magic【分治NTT】

    正题 题目链接:https://loj.ac/p/6503 题目大意 \(n\)张卡\(m\)种,第\(i\)种卡有\(a_i\)张,求所有排列中有\(k\)对相邻且相同的卡牌. \(1\leq n\ ...

  6. [loj 6496]「雅礼集训 2018 Day1」仙人掌

    传送门 Description 给出一张 \(n\)个点 \(m\)条边的无向连通图,其中每条边至多属于一个简单环,保证没有自环,可能有重边.你需要为其中每条边定向,其中第 \(i\)个点的出度不能超 ...

  7. 【线段树分治 01背包】loj#6515. 「雅礼集训 2018 Day10」贪玩蓝月

    考试时候怎么就是没想到线段树分治呢? 题目描述 <贪玩蓝月>是目前最火爆的网页游戏.在游戏中每个角色都有若干装备,每件装备有一个特征值 $w$ 和一个战斗力 $v$ .在每种特定的情况下, ...

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

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

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

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

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

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

随机推荐

  1. Docker进阶之01-Docker Compose编排工具

    Docker Compose是什么 https://github.com/docker/compose 可以按项目为单位管理多个Docker容器,Python语言开发,底层调用Docker的API接口 ...

  2. html基础和js基础

    HTML基础 html文件结构 <!DOCTYPE html> 文档类型声明 <html lang="en"></html> 是html标签,称 ...

  3. 【MongoDB】C# .Net MongoDB常用语法

    1.1.驱动安装 使用NuGet包管理器安装MongoDB C#驱动:MongoDB.Driver 1.2. C#连接MongoDB //获取MongoDB连接客户端 MongoClient clie ...

  4. 【LeetCode栈与队列#02】有效括号

    有效括号 力扣题目链接(opens new window) 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右 ...

  5. toml格式配置文件介绍

    toml官方wik toml官方文档 此次文档是以v1.0.0为例,进行说明的.如果使用到的版本不同,直接去官方文档中找对应的版本即可. 谈到配置文件,大家都能说出来好几种,比如常见的ini.xml. ...

  6. 【Azure 事件中心】Event Hubs如何获取其中存放的历史消息

    问题描述 使用Azure Event Hub服务,除了正常的生产,消费消息以外,如果想拿到Event Hub中存储的历史消息?有什么方法呢? 问题解答 获取 Event Hubs 存储的历史消息,首先 ...

  7. linux系统信息命令笔记

    1,时间和日期 2,磁盘信息 4,进程概念介绍 4.1,ps 基本命令使用 ps aux 显示内容太多了.一般用ps a 或 ps au 4.2, top命令的基本使用 top 可以动态的显示运行中的 ...

  8. Java 多态性的使用

    1 package com.bytezreo.duotai3; 2 3 /*** 4 * 5 * @Description 练习多态性的使用 6 * @author Bytezero·zhenglei ...

  9. Educational Codeforces Round 158 (Rated for Div. 2)C. Add, Divide and Floor(思维/数学)

    C. Add, Divide and Floor 这里我们选择固定最小数不变,然后每次让其他数向最小数靠近,模拟一下可以发现,只要最大值变为和最小值一样,其他都会和最小值一样. #include &l ...

  10. map 简单梳理【GO 基础】

    〇.map 简介 map 是一种无序的基于 key-value 的数据结构,Go 语言中的 map 是引用类型,必须初始化才能使用. 其中键可以是任何类型,但值必须是可比较的类型(如整数.字符串.布尔 ...