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\)
posted @ 2020-10-18 09:28  Grice  阅读(92)  评论(0编辑  收藏  举报