do_while_true

一言(ヒトコト)

2023.9 ~ 我们总这样重复分离,却要重新开始,相互送别对方,说着来世再见,再次失忆着相聚

1. CF1861F

枚举一个人最优花色是啥,调整可证把这个花色尽可能分配给他更优。然后二分答案,让其他人保证每个花色都要 \(\leq x\)

再往后是没想到的:可以先考虑一些复杂度较高的做法,比如 flow,左边 \((n-1)\) 个人右边 4 种花色,连边容量是 \(x-a_{i,j}\),左边点的容量是这个人还要拿多少张牌,右边点的容量是这个花色还剩多少张要分配。满流就 ok。

最大流转最小割,右边只有 4 个点直接状压每个点选不选,然后对于左边每个点就互相独立,可以割掉入边或者割掉所有出边选更小的那个即可。

入边容量是确定的,那么只有 \(x\leq \ ?\) 的时候才会选择割出边,否则选择割入边。排序前缀和二分即可。现在时间复杂度是 \(\mathcal{O}(4\times 2^4\times n\log n\log a)\)

感觉有点难写。Code

2. CF1864G

一个列操作了之后,这个列上的所有数都必须到自己所在行,反之同理。

两个数的偏移量相同,至少有三次操作对它们进行了操作,挑出同为行/同为列的两个操作,发现这两个操作的 \(\Delta\) 相同;反之如果行列均至少操作一次,并且有两行 \(\Delta\) 相同或者两列 \(\Delta\) 相同那么一定存在两个数偏移量相同。所以存在两个数偏移量相同当且仅当行列均操作至少一次并且存在两行/列 \(\Delta\) 相等

如果确定了每行的 \(\Delta\)\(r_i\),列的为 \(c_i\).如果存在一列没有转动,那么所有的 \(r\) 根据这一列上的元素就能确定具体的值;如果所有列都转动了,此时所有 \(r\) 必须均为 \(0\),否则一共 \(n\) 列而 \(1\leq c_i<n\) 根据鸽巢就会出现重复。

分析完性质之后尝试转,首先找出所有的合法行和合法列,这里合法定义为还没转过并且转了 \(\Delta>0\) 的偏移量之后所有数都能归位。某个时刻如果同时出现行 \(i\) 和列 \(j\) 合法,考察 \((i,j)\) 这个元素,假设先转完行,如果它需要回到原来位置需要在 \(i+r_i\) 那一列再转一下,此时 \(j\)\(i+r_i\) 这两列的偏移量相同,就不符合条件了。所以必须全都是合法列或者合法行,把它们全都转一下,它们之间顺序可以任意排列所以方案数是个阶乘。模拟下去把阶乘乘起来就行。

Code

3. the 2nd ucup stage1 B

按照花费排序之后是 \(v_1,v_2,\cdots v_k\),贪心是修改一个后缀的 LCA,枚举 \([i+1,n]\) 后缀的过程中能够维护出后缀中距离 LCA 最远点的距离(最大深度减去 LCA 深度),和 \(v_{i-1}\) 的花费取 \(\min\) 贡献到答案里面。这里出现算错就是后缀里面有一个并没有 chkmin 成功,此时不会更新答案。Code

4. the 2nd ucup stage1 F / P3513

把图划分成两个点集,一个是团,另一个是独立集。性质是团中点的度数 \(\geq\) 独立集中点的度数。先把一个合法方案构造出来,按照度数从大到小排序贪心把点加到团中然后 check 是否能够凑出一个团,加到不能加为止再 check 剩下的是否为独立集。

唯一的问题就是度数相同时的决策,为什么按照任意顺序加是对的。现在考虑一个合法方案会不会被判成不合法:

假如团的集合是 \(A\),独立集的集合是 \(B\),首先有 \(A\) 中度数均 \(\geq |A|-1\)\(B\) 中度数均 \(\leq |A|\),那么度数相同只可能是同为 \(|A|\) 或者 \(|A|-1\)

  • 如果是 \(|A|\),也就是 \(B\) 中存在点只和 \(A\) 中的相连并且都有连边。这样的点最多存在一个,大于一个那么 \(A\) 中的度数就都 \(\geq |A|+1\) 了。此时注意到度数为 \(|A|\) 的点的连边情况都是连向了所有度数 \(\geq |A|\) 的点,那么这些点之间就没有区分自然可以任意顺序加入。
  • 如果是 \(|A|-1\)\(B\) 中的点度数为 \(|A|-1\) 意味着它在 \(A\) 中仅和一个点之间没有连边,而这个点度数就是 \(|A|-1\)\(A\) 中其它的点度数都 \(\geq |A|\).此时度数为 \(|A|-1\) 的点连边情况都是连向所有度数 \(\geq |A|\) 的点,那么这些点之间也没有了区分可以任意顺序加入。Code

5. the 2nd ucup stage2 M

哎,看上去是比较套路应该很快想到题,但是完全没想到容斥,雷暴还是太强了啊啊啊啊/zk

容斥,钦定一些段它就是 \(s\),那么相当于这样把 \(w\) 生成出来:新拼上一个 \(s\) 然后拼若干个 border,或者拼上任意一个字符。

假设 \([x^i]F(x)\)\(-1\) 当且仅当 \(i\)\(s\) 的一个周期,那么拼上一个 \(s\) 再拼上若干个周期用 gf 表示出来就是 \(-\frac{x^{n}}{1-F(x)}\),然后拼上若干个字符就是 \(\frac{1}{1-26x}\),SEQ 一下再取反就是答案(最后一段的连续钦定的最后一次钦定位置是末尾,不需要乘 \(-1\)

\(\frac{x^{n}}{1-F(x)}\cdot \frac{1}{1-26x}=\frac{-x^n}{(1-F(x))(1-26x)}=\frac{P(x)}{Q(x)}\),答案的 gf 就是 \(\frac{1}{1-\frac{P(x)}{Q(x)}}=\frac{Q(x)}{Q(x)-P(x)}\),分子分母都是 \(\mathcal{O}(n)\) 项的多项式,求 \([x^m]\),是一个线性递推,然后学习了一下 bostan-mori \(\mathcal{O}(n\log n\log m)\) 解决。

Code

5. the 2nd ucup stage2 K

模拟费用流,因为费用流每次是跑最短路增广,所以只需要维护右侧 \(k\) 个点之间的最短路。对于左侧每个点会给右侧带来 \(k\) 条边,然而两点之间只有最小的那一条是有用的。所以对每个点对用一个堆维护之间连边的边权,只对每个堆堆顶以一共 \(\mathcal{O}(k^2)\) 条边跑最短路,增广之后最多改变 \(\mathcal{O}(k)\) 个左部点的匹配,再对堆进行修改即可。复杂度 \(\mathcal{O}(nk^2\log k)\)(如果我没算错的话).

Code

6. the 2nd ucup stage 2 H

本来以为是构造题,看到题解才意识到标题是关键信息(

其实是让我们构造一个静态区间半群信息查询的一个结构,上个 Sqrt Tree 就行了。

Code

7. C. 23zr提高day4雁河菊【爆标】

桶排,\(a_i\) 先和 \(i\) 取个 \(\min\),现在要求是操作使得 \(a_1=1,a_i\leq a_{i-1}+1\),令 \(b_i=a_i-i\) 那么限制变成 \(b_1=0,b_i\leq b_{i-1}\),也就是把 \(b\) 操作成不升的序列。

这里结论是不管 \(b_1=0\) 求出的答案和限制 \(b_1=0\) 是一样的,也就是一定存在最优解使得 \(b_1=0\)

由于最开始 \(a_i\)\(i\)\(\min\) 了,那么 \(b_i\leq 0\),所以 \(b_1\) 不会变大,要不然不会更优(后面的不会操作到 \(>0\) 所以 \(b_1\) 不用动)。而既然要将 \(b\) 操作成不升的序列,\(b_1\) 也不会变小要不然给后面的限制就更紧了。所以 \(b_1\) 一定不会动。

考虑最初 \(a\) 是排好序的,\(a_i\leq a_{i+1}\),所以 \(b_i-1\leq b_{i+1}\),换而言之,往后一个 \(b\),变小程度不会 \(>1\).这个时候再用 sequence 那个题的做法,并且利用 \(b_i-1\leq b_{i+1}\) 将堆换成桶来做到线性复杂度。

代码
int n,m,a[N],buf[N<<1],*vis=buf+1,tong[N];
void solve(){
	gi(n);gi(m);for(int i=1,x;i<=n;i++){gi(x);tong[x]++;}n=0;
	for(int i=0;i<=m;i++){
		while(tong[i]--)a[++n]=i;
		tong[i]=0;
	}
	ll ans=0;
	for(int i=1;i<=n;i++)if(a[i]>i)ans+=a[i]-i,a[i]=i;
	for(int i=1;i<=n;i++)a[i]-=i,a[i]=-a[i];
	vis[a[1]]++;
	int up=a[1];
	for(int i=2;i<=n;i++){
		vis[a[i]]++;
		if(a[i]>up)up=a[i];
		while(!vis[up])--up;
		if(a[i]<up){
			ans+=up-a[i],vis[up]--,vis[a[i]]++;
			if(a[i]>up)up=a[i];
		}
	}
	for(int i=1;i<=n;i++)vis[a[i]]=0;
	print(ans);pc('\n');
}

8. 【数据删除】

这让我们想起 Tutte 矩阵那里用到过的 Schwartz-Zippel,对于域 \(\mathbb{F}\) 上的一个不恒为 \(0\)\(n\)\(d\) 度多项式 \(P(x_1, x_2,\cdots, x_n)\)
\(r_1,r_2,\cdots,r_n\)\(n\)\(\mathbb{F}\) 中的独立选取的随机数,则:

\[Pr[P(r_1,r_2,\cdots,r_n) = 0]\leq \frac{d}{|\mathbb{F}|} \]

在这里为了 check 多项式系数是否为偶数,在域中需要满足 \(x+x=0\),但是模 \(2\) 的域 \(F_2\) 太小了肯定不行,于是考虑用系数模 \(2\) 的多项式环。说人话就是每个未知元用一个随机的系数模 \(2\) 的多项式(这里假定占位元是 \(x\)),然后所有运算都在模一个多项式 \(m\) 意义下进行,用二进制数表示一个多项式就行。

多项式加法肯定就是二进制数的异或(先不考虑是否需要取模),乘法咋做?考虑龟速乘,计算 \(a*b\) 的时候每次将一个 \(a*x^k\) 异或上去,现在问题就是龟速乘的时候 \(a\gets a*x\) 之后咋快速对 \(m\) 取模。

我们想让 \(a\) 总是它所在的剩余类中最小的那个,考察与 \(a\) 在同一剩余类中数有哪些,由于系数 \(\bmod\ 2\) 所以只需要考虑在 \(m,xm,x^2m\cdots\) 中选取若干个加到 \(a\) 上面就能得到 \(a\) 剩余类中的所有数。假设 \(m\) 的最高次项为 \(x^d\),此时发现这个剩余类中有且仅有一个最高次项 \(<x^d\) 的,用它当作这个剩余类的代表元即可。这个时候再考虑加法,由于每个数的最高次数 \(<x^d\),所以加法不会出现需要取模的情况,直接异或就行。

所以就二进制数 \(a\) 左移一位之后如果最高位是 \(x^d\) 了,将其异或上 \(m\) 即可。更简洁的写法是直接 \(\min(a,a\operatorname{xor}m)\),效果是一样的。在高消的时候 A'[j][k]=A[j][k]-A[i][k]*A[j][i]/A[i][i] 两边同乘 A[i][i] 之后就没有了乘法,由于只需要 check 行列式是否非 0 所以用 A[j][k]*A[i][i]-A[i][k]*A[j][i] 来作为 A'[j][k]$ 即可,只是相当于给矩阵整体乘了个 A[i][i]

这里 \(m\) 选取不可约多项式很好,EI 说随机之后有 \((1+o(1))/d\) 的概率是不可约多项式。

注记:判断不可约多项式,von zur Gathen & Gerhard 的 Modern Computer Algebra, 第 14 章

A polynomial \(f\in \mathbb{F}_q[x]\) of degree \(n\geq 1\) is irreducible if and only if

  • \(f\) divides \(x^{q^n}-x\), and
  • \(\gcd(x^{q^{n/t}}-x,f)=1\) for all prime divisors \(t\) of \(n\)

我的评价是:打住,别学了。

代码
const int mod=1000000007;
mt19937_64 rnd(time(NULL)^(ull)(new char));
const int N=61;
int val[N];
int mul(int x,int y){
	int s=0;
	while(y){
		if(y&1)s^=x;
		x<<=1;
		if(x&(1<<29))x^=mod;
		y>>=1; 
	}
	return s;
}
int getval(string &s){
	int len=s.size();
	int o=0,now=1;
	for(int i=0;i<len;i++){
		if(s[i]=='+')o^=now,now=1;
		else if(s[i]>='a'&&s[i]<='z')now=mul(now,val[s[i]-'a']);
		else now=s[i]-'0';
	}
	o^=now;
	return o;
} 
int n;
string s[N][N];
int a[N][N];
int gauss(){
	for(int i=1;i<=n;i++){
		int p=0;
		for(int j=i;j<=n;j++)
			if(a[j][i]){
				p=j;
				break;
			}
		if(!p)return 1;
		swap(a[p],a[i]);
		for(int j=i+1;j<=n;j++){
			int t=a[j][i];
			for(int k=1;k<=n;k++){
				a[j][k]=mul(a[j][k],a[i][i])^mul(a[i][k],t);
			}
		}
	}
	return 0;
}
void solve(){
	read(n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin>>s[i][j];
	for(int q=1;q<=10;q++){
		for(int i=0;i<26;i++)
			val[i]=rnd()%(1<<29);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				a[i][j]=getval(s[i][j]);
		if(!gauss()){
			puts("No");
			return ;
		}
	}
	puts("Yes");
}

9. HDU 6804 Contest of Rope Pulling

这个题的套路是 \(\pm 1\) 随机游走,前缀和最值期望只有根号,所以 random_shuffle 之后 开 \(\mathcal{O}(\sqrt n V)\) 大小的背包就行。

Code

10. HDU6413 棋盘上的旅行

另一个随机化的套路,给每个权值赋一个随机颜色,只要答案中的权值满足颜色两两不同就能得到正解。

Code

11. CF1292F Nora's Toy Boxes

够炫酷。

\(a_i\mid a_j\) 则连边 \(i\to j\).正难则反,考虑往里面加点。对每个弱连通块单独考虑。初始图中有入度 \(d=0\) 的点,对于 \(d\neq 0\) 的至少要有一个,对 \(d\neq 0\) 的点可以标记出若干 \(d=0\) 的点记作 \(T_i\),表示其后继也能选了。于是可以设计状态 \(f_{S,i}\) 表示已经标记出了集合 \(S\) 中的点,并且 \(d\neq 0\) 的已经选出来了 \(i\) 个,转移分为两类,一个是心选一个不会更新 \(S\) 的点转移到 \(f_{S,i+1}\),需要记录 \(S\) 子集内有几个 \(T\);另一个转移是枚举一个能够扩张 \(S\)\(T\) 并且转移到 \(f_{S\cup T,i+1}\)

分析一下一个弱连通块 \(d=0\) 的点有多少个,首先它要有出度所以仅考虑 \(\leq a/2\) 的点,它们两两不整除也就是一条最长反链,其 \(\leq\) 最小链覆盖,而所有奇数及其 \(2^k\) 倍数已经是一个大小为 \(a/4\) 的链覆盖。在这个分析下 \(d=0\) 的点最多 \(a/4\) 个。

那么现在这个做法是 \(\mathcal{O}(2^{a/4}n^2)\),这里记了已经选了几个点其实并不必要?因为只需要求最后选出点最多的方案,但是问题在于当前已经可以放进集合的有可能在后面才放进集合。于是想到从末状态倒着往前插(似乎正难则反第二遍又变成原问题了)这样转移的时候只需要考虑当前新增的这些用一个排列数组合进方案里即可,这样复杂度就是 \(\mathcal{O}(2^{a/4}n)\) 的了。

Code

12. CF1149D Abandoning Roads

权值为 \(a\) 的边连成了若干连通块,只有连通块之间的 \(b\) 才有用。想直接跑最短路得出答案,问题在于可能会通过走更短的几次 \(b\) 来代替在同一块内的一堆 \(a\),路径更短但是经过同一连通块两次所以不合法。那就尝试直接状压记录走了哪些连通块,由于点数 \(\leq 3\) 的连通块一定不会通过几次 \(b\) 代替一堆 \(a\)(最极限的情况就是 \(2\)\(b\) 代替 \(3\)\(a\))所以只需要记录 \(\geq 4\) 的连通块,这样复杂度就是 \(\mathcal{O}((n+m)2^{n/4})\)

Code 写了拍子才调出来我是笨b

13. CF1034C Region Separation

假设权值和是 \(S\),分成了 \(k\) 份,那么每个连通块大小 \(S/k\)\(u\) 的父边需要断当且仅当子树和 \(s_u\equiv 0\pmod {S/k}\)(证明考虑从下往上归纳)令 \(f_k\) 表示有多少个 \(u\) 满足条件,那么只有 \(f_k=k\)\(k\) 是合法的,先考虑求出 \(f\)

条件即为 \(s_u\)\(S/k\) 的倍数,那么 \(S/k\mid S_u,S/k\mid S\)\(S/k\mid \gcd(s_u,S)\),而 \(\gcd(s_u,S)\mid S\) 所以条件等价于 \(\frac{S}{\gcd(s_u,S)}\mid k,k\mid S\),将所有 \(\frac{S}{\gcd(s_u,S)}\) 标记出来作狄利克雷前缀和即可。

统计出 \(g_i\) 表示是否能分成 \(i\) 份,这样就能 dp 答案 \(dp_i=g_i\sum_{d|i}dp_d\)

Code

14. CF1770F Koxia and Sequence

流泪了咋啥也不会啊/ll

假设 \(\sum=u,OR=v\)(换个名字),or 要求每个二进制位都出现过。

Sol1:

虽然是统计异或但可以直接统计个数然后看奇偶性就行,所以可以对二进制位容斥。假设现在可以出现的二进制位是 \(a_1,a_2,\cdots\),那么想要凑出 \(u\) 就需要 \([x^u]\prod(1+x^{2^{a_i}})^n\),再拆位统计第 \(k\) 位的贡献那就看 \([x^ut]\prod_{a_i\neq k}(1+x^{2^{a_i}})^n(1+x^{2^k}(1+t))^n\) 奇偶性即可。

统计异或和的异或再令加一个元感觉比较巧妙,对于 \(2^k\) 出现了 \(p\) 次需要恰好贡献一个 \(p\),那么给 \(x^{2^k}\) 后面多带一个元 \((1+t)\),这样出现 \(p\) 次就有 \((1+t)^p\) 这一项提取一下 \([t^1]\) 就把 \(p\) 这个贡献给搞出来了。在这里能找到的灵感就是类似的去提取 \([t^k]\) 能把 \(\binom{p}{k}\) 给搞出来。

再考虑 \([t^1](1+x^{2^k}(1+t))^2\) 是偶数,而我们只关心其奇偶性所所以它直接等于 \((1+x^{2^k})^2\),这里就分析出来 \(n\) 是偶数答案就是 \(0\)\(n\) 是奇数就要算 \([x^ut]\prod_{a_i\neq k}(1+x^{2^{a_i}})^n(1+x^{2^k}(1+t))(1+x^{2^k})^{n-1}=[x^{u-2^k}]\prod_{a_i\neq k}(1+x^{2^{a_i}})^n(1+x^{2^k})^{n-1}\)

还是考虑由于只需要算奇偶性也就是 \(\bmod\ 2\) 下所以 \((1+x^{2^i})^2=(1+x^{2^{i+1}})\),所以对每个 \(i\) 记录有多少个 \((1+x^{2^i})\) 然后从低往高推就行。

Sol2:

这个做法最初转化的重点是考虑每一个位置上的数对答案的贡献是等效的(异或上统一的一个数),所以 \(n\) 是偶数的时候答案是 \(0\)\(n\) 是奇数就只需要考虑 \(a_1\) 对异或和的贡献(剩余的都根据等价性抵消掉了),现在假定 \(a_1\) 的第 \(i\) 位为 \(1\),计算方案数模 \(2\) 是多少。对 or 的限制还是考虑容斥,这样就枚举了一个集合 \(S\) 内的二进制位才能出现过,要求 \(a_1\subseteq S-\{i\},a_j\subseteq S\)

\[\sum_{\sum a=x}[a_1\in (S-2^i)]\prod_{j>1}[a_j\subseteq S]\bmod 2 \]

这里的点睛之笔是对于模 \(2\)\([x\subseteq y]=\binom{y}{x}\),所以:

\[\begin{aligned} =&\sum_{\sum a=x-2^i}\binom{S-2^i}{a_1}\prod_{j>1}\binom{S}{a_j}\bmod 2 \\ =&\binom{nS-2^i}{x-2^i}\bmod 2 \\ =&[(x-2^i)\subseteq (nS-2^i)] \end{aligned} \]

倒数第二步是范德蒙德卷积,枚举 \(i\)\(S\) 即可,问题得到解决。

Code

15. CF1656H Equal LCM Subsets

?这真能做?还真能做。从简单的情形出发,每个数都是质数次幂,这样就维护两个堆,如果其中一个堆的最大值大于另一个的最大值就 pop,如果其中一个空了就无解。

一般情况就考虑标准分解,如果存在一个 \(a_x\) 满足它的存在某个质数次幂都比所有的 \(b_i\) 大就 pop 掉 \(a_x\),如果不存在一个数需要 pop 就合法了。那么看指数就是 \(a_x>\max\{b_i\}\)\(\operatorname{lcm}\) 的问题是它可能会很大,需要用 \(\gcd\) 也就是指数上的 \(\min\) 来描述这个关系,\(a_x>b_i\) 就是 \(a_x>\min(a_x,b_i)\Rightarrow a_x-\min(a_x,b_i)>0\),对于每个 \(i\) 都要满足这个关系所以就是 \(\min_i\{a_x-\min(a_x,b_i)\}>0\),这是指数上的情况,对应回原数就是

\[\gcd_i \frac{a_x}{\gcd(a_x,b_i)}>1 \]

也就是 \(a_x\) 存在一个质数次幂满足比所有 \(b_i\) 的都大,当且仅当上式成立。用线段树对每个 \(x\) 维护之即可。每次删数查每个线段树,删完了把每个线段树对应位置的 \(\frac{a_x}{\gcd(a_x,b_i)}\) 置成 0.用 __int128 这样复杂度就是 \(\mathcal{O}(n^2(\log n+\log a))\)

Code

16. LOJ 3405「2020-2021 集训队作业」Gem Island 2

咋这也不会啊/ll

先考察最终形成 \(a_1,a_2,\cdots ,a_n\) 的出现概率,考虑倒着的过程那么第 \(k\) 步是选择一个 \(a_i\),乘上 \(\frac{(a_i-1)}{n+d-k}\),不看取的顺序 \(\frac{\prod (a_i-1)!}{(n+d-1)!/(n-1)!}\),然后每次取哪个就乘上一个多重集的排列数 \(\frac{d!}{\prod (a_i-1)!}\),于是概率就是 \(\frac{d!(n-1)!}{(n+d-1)!}=\binom{n+d-1}{d}^{-1}\)

然后就变成整数划分问题了,套路是把楼梯转一个方向,就变成用 \(\leq n\) 降序的数求和得到 \(d\),转移的时候要多乘一个组合数把留下来的那些列(转之前的)给选出来。复杂度是 \(\mathcal{O}(n^3)\)

这里比较神之一手的是考虑这个楼梯每一层的贡献,假设在第 \(j\) 层宽为 \(i\) 那么会对答案造成 \(\min(i,r)\) 的贡献,也就是恰好有 \(i\) 个数 \(\geq j\) 那么会造成 \(\min(i,r)\) 的贡献,假设方案数是 \(f(i,j)\),二项式反演计算钦定 \(i\) 个数 \(\geq j\),那么方案数是 \(\binom{k}{i}\binom{d-kj+n-1}{n-1}\),那么现在答案就是:

\[\begin{aligned} &\sum_{i=1}^n\sum_{j=1}^{d}f(i,j)\min(i,r) \\ =&\sum_{i=1}^n\sum_{j=1}^{d}\min(i,r)\sum_{k\geq i}(-1)^{k-i}\binom{k}{i}g(k,j) \\ =&\sum_{k=1}^n(-1)^{k}\binom{k}{i}\left(\sum_{j=1}^d g(k,j)\right)\left(\sum_{i=1}^k(-1)^i\binom{k}{i}\min(i,r)\right) \end{aligned} \]

这里 \(\sum_{j=1}^dg(k,j)=\binom{n}{k}\sum_{j}\binom{d-kj+n-1}{n-1}\) 发现是 \(k\) 的倍数求和,所以狄利克雷后缀和预处理出来。最后一个括号可以拆成几个 \(\binom{?}{i}(-1)^i\) 前缀和的形式上指标反转之后斜线求和就行(这里斜线求和上指标可以是负数 具体数学 P133)时间复杂度是 \(\mathcal{O}(n\log\log n)\)

这道题带来的启发是,有时候将贡献拆分,增加状态,反而会更可以简化问题。

Code

17. CF1062F Upgrading Cities

有向图拓扑排序相关的还能去考虑队列里面的数具有什么性质:在某个时刻,队列中的数两两都不可达。然后队列里面有若干点,那么还未入队的一定是它们能到达的点集的并。

现在去讨论队列 q.size() 大小:

  • q.size()=1\(x\) 能到达的点数就是总数减去已出队点数;
  • q.size()>=3:队列里面的数都不可能成为重要/次重要节点;
  • q.size()=2:两个点 \(u,v\) 已经互相不可达了,那么就看一点的后继点集是否包含另一个点,直接比对出边集合就行。(实现上直接看 \(v\to w\) 的点 \(w\) 剩余入度是否为 \(1\) 即可)。

Code

18. CF1240F Football

猜到一定全能行的结论了但完全不会做。会做 \(k=2\) 的加虚点跑欧拉回路,一个做法是每条边随机染色,对于一个节点如果有冲突的,将 \(\max\)\(\min\) 这两个颜色单独拉出来做 \(k=2\) 的情况。这里正确是因为 \(P=\sum {s_{i,j}}^2\) 并不会增加,毛估估就行

有理有据的构造是建立二分图然后对于边 \((u,v),u<v\) 在左部点 \(u\) 和右部点 \(v'\) 上连边。首先将每个度为 \(d=ak+b\) 的所有点拆成 \((a+1)\) 个点,前 \(a\) 个点度数为 \(k\) 最后一个点度数为 \(b\),染色使得每个点的邻边颜色两两不同,最后再将 \(u\)\(u'\) 合并即得到一个合法方案。

这里的染色构造思路类似网络流的增广,对于还未染色的一条边 \((u,v')\),找到 \(u\) 邻边中未出现颜色 \(a\)\(v'\) 邻边中未出现颜色 \(b\):如果能找到 \(a=b\) 那么直接染上就可以了。否则将其染成 \(a\),然后寻找 \(v'\) 颜色为 \(a\) 的出边 \((v',w)\) 将其染成 \(b\)。如果 \(w\) 没有颜色为 \(b\) 的邻边那么结束染色,否则再找到 \(w\) 颜色为 \(b\) 的邻边染成 \(a\) ...... 这样一直往后找直到某个点 \(x\) 不存在颜色为 \(a\) / \(b\) 的邻边。

这样一直往下找一定不会出现环,因为出现了环那么一定是偶环。画一下图发现此时一定产生矛盾。

Code

19. CF1268D Invertation in Tournament

写一下不是很熟的竞赛图结论:

强连通竞赛图具有哈密顿回路:构造是按照一条哈密顿路径从前往后考虑,前面已经分成了一个环 \(S\) 和一条链 \(T\),且满足总是 \(S\) 中的点连到 \(T\)。新加进一个点 \(x\) 时先将其插到 \(T\) 的尾部,如果 \(x\) 有连向 \(T\) 的边那么将 \(T\) 整合进环中即可。由于强连通所以最后 \(T\) 不会有剩余。

点数为 \(n\) 的强连通竞赛图存在大小为 \(3,4,\cdots n\) 的环:由于存在哈密顿路且长为 \(n-1\) 的环导出子图为点数 \(n-1\) 的强连通图所以仅需要证明存在大小为 \(n-1\) 的环即可归纳得证。考虑对于其中一个哈密顿回路 \(p_1,p_2,\cdots p_n\)

  • 如果除去 \(p_1\) 后剩余是一个强连通图那么即可找到长为 \(n-1\) 的环;
  • 否则剩余缩点后形成链状结构:
    • 如果存在一个强连通分量大小 \(>1\),整体的哈密顿回路在这个强连通分量中的路径可以直接跳过开头或结尾得到长为 \(n-1\) 的环;
    • 如果强连通分量大小全为 \(1\) 又因为 \(n>3\) 所以可以跳过中间某个大小为 \(1\) 的强连通分量得到长为 \(n-1\) 的环。

在这个题中,猜大部分图直接一次操作就能强连通。考虑如果缩点后链形成了 \(\geq 3\) 个强连通分量,那么非头尾强连通分量的某个点就能使得整张图强连通。

而如果只有两个强连通分量,如果其中一个强连通分量大小 \(s>3\) 那么操作不在大小为 \(s-1\) 的环中的那个点即可使得整张图强连通。

所以只有 \(n\leq 6\) 的时候可能需要操作 \(\geq 2\) 次,直接暴力即可,\(n>6\) 的时候枚举一个点翻转邻边然后利用 Landau 判一下就行。

Code

20. CF1148G Gold Experience

正难则反考虑反图,那么就是找到一个大小为 \(k\) 的集合使得它是独立集或者每个连通块大小 \(\geq 2\).先从前往后扫一遍能加就加找个独立集,如果独立集大小 \(\geq n/2\) 由于 \(2k\leq n\) 所以直接就找到答案了。否则考虑对于每个点找到它和独立集中的哪个有连边挂在它上面,那么现在就有 \(<n/2\) 个连通块,从大到小排序,能加就加。如果当前只能加一个了就在前面回退一个再加上。

Code

21. P3681 [CERC2016] 舞动的盘子 Dancing Disks

这么酷的。如果要将盘子升序放到 \((x,y)\),先将盘子分散一下每个位置降序放到 \((x,y)\) 左上的 \((xy-1)\) 个格子中,再归并起来就行。这里就可以递归,但是 \((x,y)\) 会影响其左上的状态所以先把靠右靠下的尽可能降序放然后再放自己。假设 \(f_{i,j}\)\(\leq i,\leq j\) 最终放到 \(i,j\) 能放多少盘子,于是就有 \(f_{1,1}=1\),然后 \(f_{i,j}\) 是左上所有 \(f\) 的和。

这样算出来 \(f\) 还不够,还有可以一次挪多个没用上,发现 \(f_{1,2},f_{2,1}\) 是能做到 2 的所以就做完了。

Code

22. P4740 [CERC2017] Embedding Enumeration

\(2\times n\) 足够大右边是不会溢出的。所以 \(dp_1(x)\) 表示 \(x\) 在一个 \(2\times \infty\) 网格的 \((1,1)\) 将其子树铺满的方案数(这里左侧是卡住的不能往左延伸)。

如果 \(x\) 子树已经是条链可以提前 dp 出来方案数,否则考虑 \(x\) 子树内最靠上的有两个儿子的点 \(v\),它的两个儿子是 \(p,q\),分类讨论这三点的分布即可,还需要提前 dp 出长为 \(i\) 的链且结尾右侧空的方案数(\(x\)\(v\) 的链靠上的一段是可以任意折叠的)。

这个时候多出了 \(dp_2(x,y)\) 表示 \((1,1)\)\(x\)\((2,2)\)\(y\),铺满 \(x,y\) 子树的方案数,如果 \(x,y\) 其中一者没有儿子直接返回另一者的儿子的 \(dp_1\);否则两个人都只能有一个儿子,继续返回儿子的 \(dp_2\)

记搜实现就行,每个点最多会计算一次 dp1,不难发现 dp2 计算次数也是线性的。

Code Code

posted @ 2023-09-20 21:18  do_while_true  阅读(111)  评论(3编辑  收藏  举报