题意

给定 nnn 种颜色的球,第 iii 种颜色的球数量为 aia_iai​ 个,一种排列的贡献可以如下计算:先把这个序列首尾相连,然后把所有相邻且颜色相同的段拿出来,贡献为他们的长度之积,求所有排列的贡献和,原排列不同,首尾相连后相同的排列不算同一种。模 998244353998244353998244353。


先考虑一个序列怎么做
我们对每一个 iii 枚举将 aia_iai​ 分成 bib_ibi​ 段,算出这种情况下的方案数已经每一种颜色的贡献
那么答案可以表示为(用 f(a,b)f(a,b)f(a,b) 表示把 aaa 分成 bbb 段的所有情况的系数之和)
∑bways∗∏f(ai,bi)\sum_{b}ways*\prod f(a_i,b_i)b∑​ways∗∏f(ai​,bi​)
发现 fff 就是把 aaa 分成 bbb 块然后每一块选一个的方案数,巧妙地发现 f(a,b)=(a+b−1b∗2−1)=(a+b−1a−b)f(a,b)=\binom{a+b-1}{b*2-1}=\binom{a+b-1}{a-b}f(a,b)=(b∗2−1a+b−1​)=(a−ba+b−1​)
考虑求 wayswaysways,把所有颜色放在一起容斥,枚举强制合并的端点个数
ways=∑c(∏(bi−1ci)(−1)ci)(∑bi−ci)!∏(bi−ci)!ways=\sum_{c}(\prod \binom{b_i-1}{c_i}(-1)^{c_i})\frac{(\sum b_i-c_i)!}{\prod(b_i-c_i)!}ways=c∑​(∏(ci​bi​−1​)(−1)ci​)∏(bi​−ci​)!(∑bi​−ci​)!​
那么放到一起就是,换成枚举合并之后的段数
∑b∑c∏f(ai,bi)(bi−1ci−1)(−1)bi−ci(∑ci)!∏ci!\sum_b\sum_c\prod f(a_i,b_i)\binom{b_i-1}{c_i-1}(-1)^{b_i-c_i}\frac{(\sum c_i)!}{\prod c_i!}b∑​c∑​∏f(ai​,bi​)(ci​−1bi​−1​)(−1)bi​−ci​∏ci​!(∑ci​)!​
发现后面有一个 ∏ci!\prod c_i!∏ci​!,考虑构造每一种颜色的 EGFEGFEGF
∑cxcc!∑b≥cf(ai,bi)(bi−1ci−1)(−1)bi−ci\sum_{c}\frac{x^c}{c!}\sum_{b\ge c}f(a_i,b_i)\binom{b_i-1}{c_i-1}(-1)^{b_i-c_i}c∑​c!xc​b≥c∑​f(ai​,bi​)(ci​−1bi​−1​)(−1)bi​−ci​
后面的一坨可以 NTTNTTNTT 求,然后分治 FFTFFTFFT 就可以全部乘起来

考虑环的情况怎么做
强制以 1 开头,那么 1 的生成函数的 xcx^cxc 会变成 xc−1x^{c-1}xc−1
减去强制以 1 开头,以 1 结尾的个数,这个的 xcx^cxc 会变成 xc−2x^{c-2}xc−2

但发现还是不对,如果环的循环是 TTT 的话,我们需要统计 TTT 遍,而实际上只统计了
b1∑aiT\frac{b_1}{\frac{\sum a_i}{T}}T∑ai​​b1​​ 遍,我们将第一个生成函数中含 bbb 的项除一个 b1b_1b1​,最后乘上 mmm 就可以了

#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 2e5 + 5;
int read(){int cnt = 0, f = 1; char ch = 0;while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();return cnt * f;
}
#define poly vector<int>
#define pb push_back
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
void Add(int &a, int b){ a = add(a, b); }
void Dec(int &a, int b){ a = dec(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
int coe(int a){ return (a&1)?Mod-1:1; }
int ksm(int a, int b){ int ans=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a); return ans; }
int n, m, a[N];
int fac[N], ifac[N], inv[N];
poly f[N];
int C(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fac[n],mul(ifac[n-m],ifac[m])); }
void Fac_init(int n){fac[0]=fac[1]=ifac[0]=ifac[1]=inv[0]=inv[1]=1;for(int i=2; i<=n; i++) inv[i]=mul(Mod-Mod/i,inv[Mod%i]);for(int i=2; i<=n; i++) fac[i]=mul(fac[i-1],i), ifac[i]=mul(ifac[i-1],inv[i]);
}
cs int K = 18;
poly w[K+1];
poly rev; int up, bit;
void init(int deg){up=1,bit=0; while(up<deg) up<<=1,++bit; rev.resize(up);for(int i=0; i<up; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void NTT_init(){for(int i=1; i<=K; i++) w[i].resize(1<<i-1);int wn=ksm(3,(Mod-1)/(1<<K)); w[K][0] = 1; for(int i = 1; i < (1<<K-1); i++) w[K][i]=mul(w[K][i-1], wn);for(int i = K-1; i; i--) for(int j=0; j<(1<<i-1); j++) w[i][j]=w[i+1][j<<1];
}
void NTT(poly &a, int typ){for(int i=0; i<up; i++) if(i<rev[i]) swap(a[i],a[rev[i]]);for(int i=1,l=1; i<up; i<<=1,++l)for(int j=0; j<up; j+=(i<<1))for(int k=0; k<i; k++){int x=a[k+j], y=mul(a[k+j+i],w[l][k]);a[k+j]=add(x,y); a[k+j+i]=dec(x,y);}if(typ==-1){reverse(a.begin()+1,a.end());for(int iv=ksm(up,Mod-2),i=0; i<up; i++) a[i]=mul(a[i],iv);}
}
poly operator * (poly a, poly b){int deg = a.size()+b.size()-1; init(deg); a.resize(up); b.resize(up); NTT(a,1); NTT(b,1);for(int i=0; i<up; i++) a[i]=mul(a[i],b[i]); NTT(a,-1); a.resize(deg); return a;
}
poly Solve(int l, int r){if(l==r){ for(int i=1; i<f[l].size(); i++) Mul(f[l][i], ifac[i]); return f[l]; } int mid=(l+r)>>1; return Solve(l,mid) * Solve(mid+1,r);
}
int main(){n = read();for(int i = 1; i <= n; i++) m+=a[i]=read();    Fac_init(m); NTT_init();for(int i = 1; i <= n; i++){poly g(a[i]+1, 0), h(a[i]+1, 0);for(int j = 1; j <= a[i]; j++) g[j]=mul(fac[j-1], C(a[i]+j-1,a[i]-j));if(i==1) for(int j=1; j<=a[i]; j++) Mul(g[j], inv[j]);for(int j=0; j<=a[i]; j++) h[a[i]-j] = mul(ifac[j], coe(j));g=g*h; f[i].resize(a[i]+1);for(int j=1; j<=a[i]; j++) f[i][j]=mul(g[a[i]+j], ifac[j-1]);}poly F=Solve(2,n);poly G(a[1],0);for(int i=0; i<G.size(); i++) G[i]=mul(f[1][i+1], ifac[i]);G=G*F;int ans=0;for(int i=1; i<G.size(); i++) Add(ans, mul(G[i],fac[i]));if(a[1]>1){G=poly(a[1]-1,0);for(int i=0; i<G.size(); i++) G[i]=mul(f[1][i+2], ifac[i]);G=G*F;for(int i=1; i<G.size(); i++) Dec(ans, mul(G[i],fac[i]));} cout << mul(ans, m); return 0;
}

集训队作业2018: 青春猪头少年不会梦到兔女郎学姐(多限制容斥)(生成函数)(组合数学)相关推荐

  1. 【洛谷 P6151 [集训队作业2019] 青春猪头少年不会梦到兔女郎学姐】【容斥原理+生成函数】

    题意 定义一个序列的权值为:把序列首尾相接成一个环,环上每段数字长度的乘积.有nnn种数字,求所有满足第iii种数字恰好出现aia_iai​次的排列的权值之和. n,∑ai≤2∗105n,\sum a ...

  2. 【集训队作业2018】青春猪头少年不会梦到兔女郎学姐(容斥)(分治FFT)

    简要题意: 给定 nnn 种颜色的球,第 iii 种颜色的球数量为 aia_iai​ 个,一种排列的贡献可以如下计算:先把这个序列首尾相连,然后把所有相邻且颜色相同的段拿出来,贡献为他们的长度之积,求 ...

  3. power oj 2866 青春猪头少年不做怀梦美少女的梦

    题目链接 给一个字符串, 询问其"前缀的后缀,和后缀的前缀,是某个子串"的个数 之前也不了解这个前缀后缀到底是个什么东西= = 不过按照题面对前缀后缀的解释,模拟一遍,就可以发现, ...

  4. power oj 2866青春猪头少年不做怀梦美少女的梦(寻找母串中有多少个子串)

    Description 下面解释一下什么是前缀和后缀: 字符串的前缀就是字符串的任意一个首部,他也是一个字符串,例如"abcd"他的前缀有"a","a ...

  5. UOJ#449. 【集训队作业2018】喂鸽子

    #449. [集训队作业2018]喂鸽子 DP好题 法一:min-max容斥 处理前m个,最快吃饱的鸽子期望的时间 根据期望的定义 考虑每个方案数的概率*期望次数 枚举前m个用了x个,概率都是(1/m ...

  6. uoj#422. 【集训队作业2018】小Z的礼物

    uoj#422. [集训队作业2018]小Z的礼物 题目描述 Solution 所有礼物全部取到的方案数并不好求,因此我们考虑min−maxmin-maxmin−max容斥,转化为第一次取到集合中某一 ...

  7. 【UOJ#450】【集训队作业2018】复读机(生成函数,单位根反演)

    [UOJ#450][集训队作业2018]复读机(生成函数,单位根反演) 题面 UOJ 题解 似乎是\(\mbox{Anson}\)爷的题. \(d=1\)的时候,随便怎么都行,答案就是\(k^n\). ...

  8. UOJ#418. 【集训队作业2018】三角形

    #418. [集训队作业2018]三角形 和三角形没有关系 只要知道儿子放置的顺序,就可以直接模拟了 记录历史最大值 用一个pair(a,b):之后加上a个,期间最大值为增加b个 合并? A1+A2= ...

  9. 【集训队作业2018】喂鸽子

    我的计数还是太差了-- 这道题现在知道三种做法. 1. 直接DP 首先显然需要min-max容斥(不知道请百度),不然很难算. 显然对于大小相同的集合答案一样,问题转化为求 \(f_c\) 即 \(c ...

最新文章

  1. 递归与分治之棋盘覆盖问题
  2. 快速启动神器 Wox
  3. python学生管理系统-python实现学生成绩管理系统
  4. Leetcode 204. 计数质数 解题思路及C++实现
  5. C++中多态的概念和意义
  6. 【Nutch2.3基础教程】集成Nutch/Hadoop/Hbase/Solr构建搜索引擎:安装及运行【集群环境】
  7. 查找乱码字符串的SQL
  8. 2、Redis入门介绍
  9. 如何正确的开始用Go编程
  10. 【Elasticsearch】ElasticSearch Cluster的一致性问题
  11. doctest使用注意点 -- 省略号的使用
  12. OSPF的LSA类型 ——连载二网络LSA
  13. Vue开发实例(01)之环境搭建nodejs与运行第一个Vue项目
  14. html网页设计模板
  15. ae合成设置快捷键_AE设计首选快捷键大全+解析
  16. android+属性动画+高度,android 自定义view+属性动画实现充电进度条
  17. 游戏辅助 -- 走路call中ecx值分析
  18. group normalization
  19. C#编写的串口调试软件,下位机传过来的中文全是问号???
  20. Java——常用开发工具

热门文章

  1. 如何防守住企业的生死大门?
  2. 金亚科技董事长 周旭辉 访谈录
  3. 第四章第十三题(判断元音还是辅音)(Vowel or consonant?)
  4. gif在html里为何会自动停止,CSS或JS实现gif动态图片的停止与播放
  5. K8S网络模型原理剖析和实践-杜军-专题视频课程
  6. 用ECS做HexMap:高地与阶梯
  7. 《介绍一款开源的类Excel电子表格软件》续:七牛云存储实战(C#)
  8. 深度经验总结:快逸报表工具单数据集版本和多数据集版本的主要区别之一
  9. ppt高级动画效果如何循环起来?
  10. python文本文件和二进制文件的区别_以文本格式和二进制格式打开文件,到底有什么区别?...