HN省集模拟赛第一场
A
求解长度为 \(n\) 的序列 \(A\) 数量,使得
- \(\forall i\in [1,n],A_i \in [1,m]\)
- \(\forall i\in [1,n),A_{i+1}\ne A_i\)
- \(\forall i\in [1,n-m+1],\{A_i,A_{i+1},\dots,A_{i+m-1}\}\ne\{1,\dots,m\}\)
- \(|\{ A_i\mid i\in[1,n]\}|=m\)
首先最后一个条件没啥用,我们可以二项式反演,令 \(f_i\) 表示 \(|\{ A_j\mid j\in[1,n]\}|=i\) 的序列数量。
我们记 \(g_i\) 为 \(\{ A_j\mid j\in[1,n]\}\subseteq \{1,\dots,i\}\) 的方案数。
那么有
考虑 \(g_m\) 怎么算。
考虑容斥。
我们假设,容斥了 \([p_1,p_1+m-1],\dots,[p_k,p_k+m-1]\) 这些区间为排列,考虑怎么算方案数。
那么我们可以分成若干段,每个段互不相交。
每一段可以看成一个长度为 \(m\) 区间,后面跟着若干长度小于 \(m\) 的排列。
那么就是 \((-1)^k(m-1)(m-1)!\prod_{i=1}^{k-1}(p_{i+1}-p_i)\)(\(p_1>1\)) 或 \((-1)^km!\prod_{i=1}^{k-1}(p_{i+1}-p_i)\)(\(p_1=1\))(假设有交)
我们考虑这个东西的生成函数,令 \(a_i\) 为长度为 \(i\) 的每个位置被排列覆盖带容斥系数和。(假装 \(p_1>1\))
令 \(G=\sum_{i=1}^{m-1}i!z^i\):

那么考虑把未覆盖的和一些段组合起来,那就是 \(\dfrac{1}{1-(m-1)z-F}\)。
现在考虑从 \(1\) 开始的排列,就乘上 \(\dfrac{m}{m-1}\),于是 \(g_m\) 是 \([z^n]\dfrac{m}{m-1-(m-1)^2z+\dfrac{(m-1)^2(m-1)!z^m}{1+G}}=[z^n]\dfrac{m+mG}{(m-1-(m-1)^2z)(1+G)+(m-1)^2(m-1)!z^m}\)。
直接 BM 算法就过了。
BM 算法:求 \([x^n]\dfrac{P(x)}{Q(x)}\)。
上下同乘 \(Q(-x)\),注意到 \(Q(x)Q(-x)\) 是偶函数,于是奇数次项系数都为 \(0\)(否则总可以找到值使得其不为偶函数),记 \(Q_0(x^2)=Q(x)Q(-x)\),\(P(x)Q(-x)=P_0(x^2)+xP_1(x^2)\),那么就是
递归下去就可以了,边界就是 \(n\) 变成 \(0\),此时就是 \(\dfrac{P(0)}{Q(0)}\)。
B
给定序列 \(\{f_i\}_{i=0}^{2^n-1},\{F_i\}_{i=0}^{2^n-1}\),求:
考虑子集反演,令
那么答案:
右边两个就是高维差分。
然后中间这个暴力 FWT 就可以做到 \(\mathcal{O}(n3^n)\)。
使用递推可以做到 \(\mathcal{O}(3^n)\),但是被卡空间,但是更改顺序就可以过了。
#include<bits/stdc++.h>
using namespace std;
int n;
const int P=998244353;
int f[2][1<<17],F[1<<17];
int tail,tmp[20][1<<17],ans;
void dfs(int d,int s){
if(s==0){
for(int i=0;i<(1<<n);++i){
tmp[tail][i]=F[i];
ans=(ans+(long long)f[0][i]*f[1][i]%P*F[i]%P*F[i])%P;
}
}
else{
int num=((1<<n)-1)^s;
int k=s&(-s);
for(int i=num;;i=(i-1)&num){
tmp[tail][i]=tmp[tail-1][i]+tmp[tail-1][i^k];
if(tmp[tail][i]>=P) tmp[tail][i]-=P;
ans=(ans+(long long)f[0][s|i]*f[1][i]%P*tmp[tail][i]%P*tmp[tail][i])%P;
if(!i) break;
}
}
if(d==-1){
return;
}
++tail;
for(int i=0;i<=d;++i){
dfs(i-1,s|(1<<i));
}
--tail;
}
int main(){
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
for(int i=0;i<(1<<n);++i){
cin>>f[0][i];
f[1][i]=f[0][i];
}
for(int i=0;i<(1<<n);++i){
cin>>F[i];
}
for(int k=0;k<n;++k){
for(int i=0;i<(1<<n);++i){
if(!((i>>k)&1)){
f[0][i]-=f[0][i|(1<<k)];
if(f[0][i]<0) f[0][i]+=P;
}
}
}
for(int k=0;k<n;++k){
for(int i=0;i<(1<<n);++i){
if((i>>k)&1){
f[1][i]-=f[1][i^(1<<k)];
if(f[1][i]<0) f[1][i]+=P;
}
}
}
dfs(n-1,0);
cout<<ans;
return 0;
}
C
对于一个长度为 \(n\) 的排列 \(p\) 和整数 \(1\le x\le n\),我们想要这个排列中不出现值包含 \(x\) 的逆序对。每一次次数你可以选中 \(p\) 的子区间 \(p[l\dots r]\),将其挪到开头和末尾,定义 \(f(p,x)\) 为将其变得不出现值包含 \(x\) 的逆序对的操作次数的最小值。对于一个排列 \(p\),定义其权值 \(w(p)=\sum_{i=1}^{n}f(p,i)\)。
给定 \(m\),求 \(w(p)\le m\) 的排列 \(p\) 数量。
首先注意到
考虑从小到大填数,令 \(dp_{i,j,k,\mathscr{l}}\quad (\mathscr{l}\in\{0,1\})\) 表示填了 \(1\sim i\) 的数,形成 \(j\) 个连续段,目前累计和为 \(k\),第一个填或没填。注意就像很多线头 dp,我们一开始并不关心每个段的具体位置,只知道两个段之间不能相连。
考虑贡献,考虑刷表。
接下来考察填 \(i\) 的位置。
-
若 \(\mathscr{l}=0\) 且 \(j>0\),可以填在开头,与第一个段接在一起,\(dp_{i+1,j,k+j,1}\leftarrow dp_{i,j,k,0}\)。
-
若 \(\mathscr{l}=0\),可以填在开头,新开一段,\(dp_{i+1,j+1,k+j,1}\leftarrow dp_{i,j,k,0}\)。
-
新开一段,\(dp_{i+1,j+1,k+j-\mathscr{l}+1,\mathscr{l}}\leftarrow (j+1-\mathscr{l})\times dp_{i,j,k,\mathscr{l}}\)。
-
延续某个段(这里若开头没有填过,那么也不填到开头,否则会算重,若开头填过,则不能从前延续第一个段),填在前面:\(dp_{i+1,j,k+j-\mathscr{l}+1,\mathscr{l}}\leftarrow (j-\mathscr{l})dp_{i,j,k,\mathscr{l}}\)。填在后面:\(dp_{i+1,j,k+j-\mathscr{l},\mathscr{l}}\leftarrow j\times dp_{i,j,k,\mathscr{l}}\)。
-
合并两个段,\(dp_{i+1,j-1,k+j-\mathscr{l},\mathscr{l}}\leftarrow (j-1)\times dp_{i,j,k,\mathscr{l}}\)。
然后这样似乎是 \(\mathcal{O}(n^2m)\) 的,无法通过。
但是注意到 \(m>3000\) 时答案就是 \(n!\) 了,于是实际复杂度可以通过。
A
B
草。
给定 \(n,\{a_i\}_{i=1}^{\lfloor \sqrt{n} \rfloor}\) 和 \(k\),求
其中 \(v(i)\) 是 \(i\) 的最大平方因子
答案就是
这可以 min_25 筛。
当然,还有其它做法。
考虑 \(f(i)=\sum_{v(j)=i,j\le n}j^k\),令 \(g(i)=\sum_{i^2\mid j,j\le n}j^k\)。
那么显然有
莫反就得到
答案是
这个前面的直接迪克利雷卷积。
后面的呢?
后面的是自然数幂和。
自然数幂和怎么做?
因为 \(k \le 10^6\),所以我们可以拉格朗日插值,在 \(\mathcal{O}(k)\) 的复杂度内求出一个自然数幂和。
但是我们不能算很多这样的自然数幂和,假设算 \(B\) 个,那么复杂度是 \(\mathcal{O}(Bk+n/B^2)\),当 \(B=\mathcal{O}(\sqrt[3]{\dfrac{n}{k}})\) 时取得最小值 \(\mathcal{O}(n^{\frac{1}{3}}k^{\frac{2}{3}})\),由于拉格朗日插值法常数大可以调整一下实际 \(B\)。
还有一个细节,我们这里最好不要带 log,所以要在线性复杂度内处理出 \(i=1\dots n/B^2\) 的 \(i^k\)。
怎么做?
注意到 \(i^k\) 是积性函数,直接线性筛即可。
C
求长度为 \(n\) 的值域在 \(1\sim m\) 的序列众数期望数量。
min-max 容斥,记第 \(i\) 种数出现次数为 \(cnt_i\),那么就有
注意到应有 \(ij\le n\),否则是不可能的。
于是我们只用算当前 \(i\) 种数出现次数至少为 \(j\) 的概率。
这个可以直接 dp,令 \(dp_{i,j,k}\) 表示有 \(i\) 种数,出现次数至少为 \(j\),出现次数和为 \(k\) 的方案数,每一次转移枚举有多少种数出现次数恰好为 \(j\)。
这样复杂度是 \(\mathcal{O}(n^3)\),常数较小,可以通过。
A
构造 \(1\dots n\) 的排列 \(a,b\),使得对于 \(i=1\dots n,|\sqrt{i}+\sqrt{a_i}+\sqrt{b_i}-2\sqrt{n}| \le 2.5\)。
做法1
先不管 \(2.5\),我们想最小化 \(\sqrt{i}+\sqrt{a_i}+\sqrt{b_i}-2\sqrt{n}\),除以 \(\sqrt{n}\),变成 \(\sqrt{\dfrac{i}{n}}+\sqrt{\dfrac{a_i}{n}}+\sqrt{\dfrac{b_i}{n}}-2\)。我们假装 \(\sqrt{\dfrac{a_i}{n}},\sqrt{\dfrac{b_i}{n}}\) 是 \((0,1)\) 间的任意实数,记为 \(x_i,y_i\),那直接让 \(x_i+y_i=2-\sqrt{\dfrac{i}{n}}\),然后把它们排序后分配回 \(\sqrt{\dfrac{ranking}{n}}\) 的形式。
观察一下当 \(n\) 很大时 \(\sqrt{\dfrac{i}{n}}\) 就比较均匀,所以直接随机一个 \(x_i,y_i\)。
做法2
考虑知道了 \(a\) 怎么确定 \(b\)。
直接将 \(\sqrt{i}+\sqrt{a_i}\) 排序后从大到小分就行。
但这样显然很劣,\(a,b\) 是对称的,可以通过 \(b\) 再确定 \(a\),一开始随机一个 \(a\),反复这么做就可以是对的了。
然后还可以以一定概率随机交换,这样可以搞到 \(0.5\)。
做法3
我们把 \(n\) 个数排成三角形,那么一个位置的根号大概是到顶点的深度。
一个位置可以注意到这个到三个顶点的和是定值,恰好就是 \(2\sqrt{n}\) 左右。
所以旋转到另外两个顶点标号,就得到答案了。
如果填不满,那么也是可以的,直接不管就可以。
B
C
强强题。
给定 \(n\),求有多少 \(0\dots n\) 的排列 \(p_0,\dots,p_n\) 满足,对于任意 \(0\le a<b<c<d\le n\) 且 \(a+d=b+c\),则 \([\min(p_a,p_d),\max(p_a,p_d)]\) 和 \([\min(p_b,p_c),\max(p_b,p_c)]\) 包含或不交。
首先第一步考虑如何刻画这个条件。
我们先考虑逆排列 \(q\),那么就成了对于任意 \(a<d,b<c,p_a+p_d=p_b+p_c\),满足 \([a,d],[b,c]\) 相交或不交。
显然的是这有循环性,我们可以钦定 \(q_0=0\),最后答案乘上 \(n+1\)。
接下来我们证明:
任意合法排列 \(q\)(\(q_0=0\)),与所有分数 \(\alpha=\dfrac{p}{q}\in (0,1],q\le n\) 存在一一对应关系。
先考虑从 \(\alpha\) 到 \(q\)。
我们这样构造:
对于 \(0\le i\le n\),我们将其放在 \(\{\alpha i\}\) 的位置,最后从小到大扫(相同位置编号小的优先)得到的排列就是合法的。
证明是简单的,考虑 \(a+d=b+c\),可以知道 \(\dfrac{\{\alpha a\}+\{\alpha d\}}{2}-\dfrac{\{\alpha b\}+\{\alpha c\}}{2}=0,-\dfrac{1}{2},\dfrac{1}{2}\),若为 \(0\) 显然可行,若为 \(\pm \dfrac{1}{2}\) 那么如果相交其总长必定大于等于 \(1\),这是不可能的。
从 \(q\) 到 \(\alpha\),考虑归纳:
奠基:\(n=1\) 时满足条件。
递推:对于每个 \(q\) 考虑删去 \(n\),令 \(\alpha^{\prime}\) 为删去 \(n\) 后
A
懒得写了,板子。
B
给定 \(m,n,L,K\) 和区间序列 \([l_1,r_1],[l_2,r_2],\dots,[l_n,r_n]\subseteq [0,2^m)\),而且 \(r_1-l_1+1=r_2-l_2+1=\dots=r_n-l_n+1=L\),对于每个 \(k=0\dots 2^m-1\),求 \(n+N+1\) 元组 \((a_1,\dots,a_n,T,S_1,\dots,S_K)\) 的数量,满足
- \(S_1,\dots,S_K \subseteq T \subseteq U=\{1,\dots,n\}\)。
- \(a_i\in [l_i,r_i]\)。
- \(\bigoplus\limits_{i=1}^{K}\bigoplus\limits_{j\in S_i}a_j=k\)。
发现 \(T\) 无关紧要,可以看成贡献为 \(2^{n-|\bigcup_{i=1}^{K}S_i|}\),可以写出集合幂级数:
这里 \(x^p\cdot x^q=x^{p\oplus q}\)。
化简,得:
FWT,即求:
接下来是场上做法:
考虑分治维护这个区间内的乘积,我们发现跨过分支中心的本质不同区间只有 \(L-1\) 个!
先考虑左右儿子合并,发现右儿子乘到左儿子去会多一个负号,所以我们维护
然后区间就暴力乘。
这样子复杂度是 \(\mathcal{O}(mL2^m)\),无法通过。
怎么优化?
我们不分治了!
将

浙公网安备 33010602011771号