LOJ#6503.「雅礼集训 2018 Day4」Magic[容斥+NTT+启发式合并]
题意
\(n\) 张卡牌 \(m\) 种颜色,询问有多少种本质不同的序列满足相邻颜色相同的位置数量等于 \(k\)。
分析
首先本质不同不好直接处理,可以将同种颜色的卡牌看作是不相同的,求出答案后除以 \(\prod {a_i!}\) 即可。
如果我们能够得到一个至少存在 \(k\) 个魔术对的排列数,就可以容斥了。
考虑单独处理每种颜色, 枚举一个颜色 \(i\),计算这种颜色至少有 \(j\) 对的方案总数。
可以选择 \(j\) 张牌保证这些牌一定跟在某张牌的后面,这样就可以形成 \(\geq j\) 个满足要求的魔术对了。
然后做一个背包。
定义状态 \(f_{i,j}\) 表示处理了前 \(i\) 种颜色,至少存在 \(j\) 对魔术对的排列数。
对于 \(f_{m,j}\),剩下的 \(n-j\) 张牌可以任意排列。背包是一个卷积的形式可以 NTT 优化。
合并背包的过程可以用堆维护,每次合并堆顶最小的两个背包数组,复杂度类似启发式合并。
所以总时间复杂度为 \(O(n\log^2n)\)。
技巧:在计算方案出现困难的时候考虑容斥简化条件(类似反演题目的思想)
代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
typedef pair<int,int> pii;
#define mp make_pair
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=1e5 + 7,mod=998244353;
int n,m,k,K,len,lst,sz[N<<1],a[N];
LL invfac[N],inv[N],fac[N];
vector<LL>v[N<<1];
priority_queue<pii,vector<pii>,greater<pii> >Q;
void add(LL &a,LL b){a+=b;if(a>=mod) a-=mod;}
LL Pow(LL a,LL b){
LL res=1ll;
for(;b;b>>=1,a=a*a%mod) if(b&1) res=res*a%mod;
return res;
}
LL Inv(LL a){return Pow(a,mod-2);}
LL C(int n,int m){
return fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}
void ntt(vector<LL> &c,int n,int f){
for(int i=0,j=0;i<n;++i){
if(i<j) swap(c[i],c[j]);
for(int k=n>>1;(j^=k)<k;k>>=1);
}
for(int i=1;i<n;i<<=1){
LL wn=Pow(3,(mod-1)/(i<<1));
if(f==-1) wn=Inv(wn);
for(int j=0;j<n;j+=i<<1){
LL w=1;
for(int k=0;k<i;++k,w=w*wn%mod){
LL x=c[j+k],y=w*c[j+k+i]%mod;
c[j+k]=(x+y)%mod;
c[j+k+i]=(x-y+mod)%mod;
}
}
}
if(f==-1){LL inv=Inv(n);for(int i=0;i<n;++i) c[i]=c[i]*inv%mod;}
}
int main(){
m=gi(),n=gi(),K=gi();
fac[0]=invfac[0]=inv[1]=1;
rep(i,1,n){
if(i^1) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
fac[i]=fac[i-1]*i%mod;
invfac[i]=invfac[i-1]*inv[i]%mod;
}
rep(c,1,m){
sz[c]=a[c]=gi();int x=a[c];
Q.push(mp(sz[c],c));
v[c].resize(x+7);
rep(i,0,x-1) v[c][i]=C(x,i)*fac[x-1]%mod*invfac[x-i-1]%mod;
}
while(!Q.empty()){
int x=Q.top().second;Q.pop();
if(Q.empty()) { lst=x; break; }
int y=Q.top().second;Q.pop();
for(len=1;len<=sz[x]+sz[y];len<<=1);
v[x].resize(len+7);
v[y].resize(len+7);
ntt(v[x],len,1);
ntt(v[y],len,1);
for(int i=0;i<len;++i) v[x][i]=v[x][i]*v[y][i]%mod;
ntt(v[x],len,-1);
sz[x]+=sz[y];
v[y].clear();
Q.push(mp(sz[x],x));
}
LL ans=0;
rep(i,K,n-1)
add(ans,(i-K&1?mod-1:1)*v[lst][i]%mod*C(i,K)%mod*fac[n-i]%mod);
rep(i,1,m) ans=ans*invfac[a[i]]%mod;
printf("%lld\n",ans);
return 0;
}
LOJ#6503.「雅礼集训 2018 Day4」Magic[容斥+NTT+启发式合并]的更多相关文章
- Loj #6503. 「雅礼集训 2018 Day4」Magic
Loj #6503. 「雅礼集训 2018 Day4」Magic 题目描述 前进!前进!不择手段地前进!--托马斯 · 维德 魔法纪元元年. 1453 年 5 月 3 日 16 时,高维碎片接触地球. ...
- LOJ6503. 「雅礼集训 2018 Day4」Magic(容斥原理+NTT)
题目链接 https://loj.ac/problem/6503 题解 题中要求本质不同的序列数量,不太好搞.我们考虑给相同颜色的牌加上编号,这样所有牌都不相同.那么如果我们求出了答案,只需要将答案除 ...
- Loj#6503-「雅礼集训 2018 Day4」Magic【分治NTT】
正题 题目链接:https://loj.ac/p/6503 题目大意 \(n\)张卡\(m\)种,第\(i\)种卡有\(a_i\)张,求所有排列中有\(k\)对相邻且相同的卡牌. \(1\leq n\ ...
- 【loj#6503.】「雅礼集训 2018 Day4」Magic(生成函数+容斥)
题面 传送门 题解 复杂度比较迷啊-- 以下以\(n\)表示颜色总数,\(m\)表示总的卡牌数 严格\(k\)对比较难算,我们考虑容斥 首先有\(i\)对就代表整个序列被分成了\(m-i\)块互不相同 ...
- 2018.10.27 loj#6035. 「雅礼集训 2017 Day4」洗衣服(贪心+堆)
传送门 显然的贪心题啊...考试没调出来10pts滚了妙的一啊 直接分别用堆贪心出洗完第iii件衣服需要的最少时间和晾完第iii件衣服需要的最少时间. 我们设第一个算出来的数组是aaa,第二个是bbb ...
- LOJ #6509. 「雅礼集训 2018 Day7」C
神仙题 LOJ #6509 题意 给定一棵树,点权为0/1,每次随机一个点(可能和之前所在点相同)走到该点并将其点权异或上1 求期望的移动距离使得所有点点权相同 题解 根本不会解方程 容易发现如果一个 ...
- loj 6037 「雅礼集训 2017 Day4」猜数列 - 动态规划
题目传送门 传送门 题目大意 有一个位置数列,给定$n$条线索,每条线索从某一个位置开始,一直向左或者向右走,每遇到一个还没有在线索中出现的数就将它加入线索,问最小的可能的数列长度. 依次从左到右考虑 ...
- Loj 6036 「雅礼集训 2017 Day4」编码 - 2-sat
题目传送门 唯一的传送门 题目大意 给定$n$个串,每个串只包含 ' .问是否可能任意两个不同的串不满足一个是另一个的前缀. 2-sat的是显然的. 枚举每个通配符填0还是1,然后插入Trie树. 对 ...
- LOJ #6037.「雅礼集训 2017 Day4」猜数列 状压dp
这个题的搜索可以打到48分…… #include <cstdio> #include <cstring> #include <algorithm> ; bool m ...
随机推荐
- python if 判断
#!/usr/bin/env python# -*- conding:utf-8 -*- if 条件: 执行1 执行2else: 执行3 if else 后面需要加: python严格缩进,内容1和内 ...
- Oracle EBS AP 取消付款
--取消付款 created by jenrry 20170425 declare l_return_status varchar2(50); l_msg_count number; l_msg_da ...
- Huawei DHCP 全局配置与接口配置
网络拓扑图如下所示: 说明: 1.交换机Ge0/0/1口和Ge0/0/2口配置基于全局的DHCP: 2.交换机Ge0/0/3口配置基于端口的DHCP: 3.交换机上配置vlan 10 .vlan 20 ...
- [Spark RDD_add_2] Spark RDD 分区补充内容
[Spark & Hadoop 的分区] Spark 的分区是切片的个数,每个 RDD 都有自己的分区数. Hadoop 的分区指的是 Reduce 的个数,是 Map 过程中对 Key 进行 ...
- 【转】Spring学习---Spring 学习总结
什么是Spring ? Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson在其著作Expert One-On-One J2EEDev ...
- 乘风破浪:LeetCode真题_030_Substring with Concatenation of All Words
乘风破浪:LeetCode真题_030_Substring with Concatenation of All Words 一.前言 这次我们还是找字符串的索引,不过,需要将另一个字符串列表中的 ...
- [提权]域内提权神器 MS14-068 完整EXP
可以让任何域内用户提升为域管理员 c:\python27\python.exe ms14-068.py -u k8test3@k8.local -p k8team!@# -s S-1-5-2 ...
- 【Java集合源代码剖析】ArrayList源代码剖析
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/mmc_maodun/article/details/35568011 转载请注明出处:http:// ...
- metamask-iframe-stream,没成功
https://github.com/kumavis/iframe-stream/blob/master/test/rebundle.js iframe-stream-其实就是将iframe打包成流 ...
- Node.js实战(八)之回调函数
Node.js 异步编程的直接体现就是回调. 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了. 回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都 ...