2020牛客暑期多校训练营
暑假打的是HDU多校,没报牛客,来补补题
Eazy
- 题意:给定\(n,m,k\),求\(\sum\limits_{\{a_i\}\{b_i\},a>0,b>0,|a|=|b|=k}[\sum\limits_{j=1}^k a_j=n][\sum\limits_{j=1}^k b_j=m]\prod\limits_{j=1}^k min(a_j,b_j)\)
- 做法:
考虑二元生成函数
\(\begin{aligned}G(x,y)&=\sum\limits_{i,j>0}min(i,j)x^iy^j\\ &=\sum\limits_{i>0}ix^i\sum\limits_{j\ge i}y^j+\sum\limits_{i>0}iy^i\sum\limits_{j>i}x^j\\ &=\sum\limits_{i>0}ix^iy^i(\frac{1}{1-y}+\frac{x}{1-x})\\ &=\frac{xy}{1-xy}(\frac{1}{1-y}+\frac{x}{1-x})\\ &=\frac{xy}{(1-xy)(1-x)(1-y)}\\ \end{aligned}\)
\(Ans=[x^ny^m]G(x,y)^k\)
Easy construction
- 题意:给定一棵树,多次询问,给出\((l,r,x)\),求\(\sum\limits_{l\le i<j\le r}[lca(i,j)=x]\)
- 做法:
即求\({size_x\choose 2}\sum\limits_{v\in son_x}{size_v\choose 2}\)
考虑链分治,对重儿子直接主席树查询;至于轻儿子,可以对\((l,r)\)离线下来莫队,对于每个点\(i\),计算其到根路径对祖先的贡献。这样复杂度是\(O(nlogn+n\sqrt{n}logn)\)的
但是还不够,考虑对树链剖分变形
对于每个点,令子树大小前\(O(\sqrt{n})\)大的为重儿子,对于每个点,每跳一次轻边,子树大小乘以\(O(\sqrt{n})\),故只会经过\(O(1)\)次轻边
对于重儿子,即查询对于区间\([l',r']\)有多少个小于等于某个数的个数,共\(O(n\sqrt{n})\)个查询,对\([l',r']\)差分处理,配合\(O(\sqrt{n})\)修改-\(O(1)\)查询的值域分块
总复杂度\(O(n\sqrt{n})\)
NeoMole Synthesis
- 题意
- 做法:
枚举任意点为\(T\)的根,由于\(\sum |T'_i|\le 500\),讲模板树重新标号,使得不同模板树上无相同节点
令\(f_{i,j,k}\)为\(T\)中点\(i-fa_i\)匹配模板树中的\(j-k\)的最小花费(除正在匹配的这棵树,其他树均匹配完了)。特殊的,若\(k=0\),则正在匹配的模板树匹配
令\(g_i\)为\(T\)中点的子树全部匹配完的最小花费:\(g_i=min(f_{i,j,0})\)
容易发现\(f\)的转移是二分图完备匹配,用KM算法。总复杂度\(O(n^4)\)
考虑优化,容易发现\(f_{i,j,k_1\neq 0}\)只用从\(f_{i,j,k=0}\)的二分图中\(k_1\)退一次流即可
退流的过程是交替走匹配边/非匹配边,用floyd优化。
若将\(deg_i,deg_j\)一起做,复杂度\(\sum\limits_{i,j}(deg_i+deg_j)^3=n^4\)
我们可以仅对\(deg_j\)做,对于两个点\(x,y\),令其匹配点为\(x',y'\),初始化\(dis(x,y)=-w_{x,x'}+w_{y,x'}\)
则对于退流的两个点\(a,b\),令\(b\)的匹配点为\(b'\),退流的流量为\(dis_{a,b}-w_{b,b'}\)
\(\sum\limits_{i\in T'}deg_i^2\frac{n}{deg_i}=O(n^3)\)
放一份KM-bfs的板子
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define IL inline
typedef long long LL;
const int N = 400 + 3;
const int INF = 0x3f3f3f3f;
struct Kuhn_Munkers {
int n;
int W[N][N];
int Lx[N],Ly[N];
int left[N];
int slack[N];
int pre[N];
bool T[N];
IL void init(int n) {
this->n = n;
for(int i=1;i<=n;i++) fill(W[i],W[i]+1+n,INF);
}
IL void bfs(int u) {
fill(slack,slack+1+n,INF);
fill(pre,pre+1+n,0);
int x,y=0,yy=0,a;
left[y] = u;
for(;;) {
x = left[y]; a = INF, T[y] = true;
for(int i=1;i<=n;i++) if(!T[i]){
if(slack[i] > Lx[x]+Ly[i]-W[x][i]) {
slack[i] = Lx[x] + Ly[i] - W[x][i];
pre[i] = y;
}
if(slack[i] < a) a = slack[i],yy = i;
}
for(int i=0;i<=n;i++) {
if(T[i]) { Lx[left[i]] -= a; Ly[i] += a;}
else slack[i] -= a;
}
y = yy;
if(!left[y]) break;
}
while(y) left[y] = left[pre[y]], y = pre[y];
}
IL int KM() {
fill(Lx,Lx+1+n,0);
fill(Ly,Ly+1+n,0);
fill(left,left+1+n,0);
for(int i=1;i<=n;i++) {
fill(T,T+1+n,false);
bfs(i);
}
int ans = 0LL;
for(int j=1;j<=n;j++) ans += W[left[j]][j];
return ans;
}
}solver;
int n;
int p[N];
LL a[N],b[N],c[N];
int main() {
scanf("%d",&n); solver.init(n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
int v = 0;
for(int k=1;k<=n;k++) if(b[i]+c[j] > a[k]) v += p[k];
solver.W[i][j] = v;
}
}
printf("%d\n",solver.KM());
return 0;
}
Disgusting Relationship
- 题意:
令\(n\)置换环长为\(i\)的个数为\(a_i\)个,令\(f(a_1,a_2,\cdots,a_n)\)为环长为\(i\)的个数有\(a_i\)个的方案数
给定\(n,p\)(\(p\)为个数),求有多少个序列\(\{a_i\}\)使得\(p\)不整除\(f(a)\) - 做法:
\(f(a)=\dfrac{n!}{\prod\limits_{i=1}^n i^{a_i}a_i!}\)
题目可以转化为最大化分母中质因子\(p\)的次幂
结论1:若\(a_k>0(k>p)\)则不优
令\(a_1=n\),可得分母中质因子\(p\)的次幂最大为\(\sum\limits_{i=1}^{\infty}\frac{n}{p^i}\)
令\(a_1=n-\frac{n}{p}\times p,a_p=\frac{n}{p}\),此时次幂为\(\frac{n}{p}+\sum\limits_{i=2}^{\infty}\frac{n}{p^i}\)
结论2:令\((a_1,a_2,\cdots,a_m)_p=n\),\(a_i(i<m)\)上的每一个\(1\)要么在\(a_1\)要么在\(a_p\)(根据Kummer定理易证)
\(ans=p_{n\%p}\times\prod\limits_{i=1}^{m-1}(b_i+1)\)(其中\(p_i\)是\(i\)的分拆数方案数)
Decrement on the Tree
- 题意
给定一棵带边权树,\(m\)次修改一条边的边权。对于一棵树,每次可以选择一条路径将其权值\(-1\),求最少多少次可以使树边权全为\(0\) - 做法
对于一个点,其边可以两两配对
令边权和为\(sum\),最大边权为\(mx\),若\(mx>sum-mx\),贡献为\(2mx-sum\)。若\(mx\le sum-mx\),若为奇数贡献为\(1\),否则为\(0\)