2022.03.10省选模拟赛总结

(信心满满210,吃完饭炸成110……)

1.时间安排

7:30~8:10 看题面(临时更换T1)

T1:显然网络流,但是暴力很不好打啊……

T2:签到20,第二档限制度数<=20可能是点分树?

T3:签到30,第二档可以大力dp一下。

8:10~10:00 T1

搜索量巨大,暴力根本跑不动,只能跑5以内的数据,也懒得优化了,直接硬上网络流。

每行棋子个数>=x相当于空格个数<=n-x(列同理)
换句话说,一个全是棋子的棋盘,已经挖了一些空格,最多可以再挖多少个空格。
然后就变成最大流了?
起点和每个格子连一个容量为1的边,已经空的格子不连,每行的x=n-x-这行已经空的格子数,列同理。
但是怎么同时处理行和列的关系呢?
如果一个点被选了,根据最大流的反悔,可能只算行和列其中一个的贡献,那就寄了。

或者转化成最小割?
但同样遇到了同时处理行列的问题……

能不能证出来一个东西:行和列同时最大流的情况下,取min一定都能满足且最大。
显然不对吧……

或者说最大流跑完后再找一遍所有点,只把行列都流满的点算上?

可能可行,试试。

完全不行……

先思考怎么样能让选择一个棋子后必须让流流向对应的行和列。
如果有什么办法能把行和列绑定起来就好了。
先用行跑一遍,跑出来每行最多分多少流后再跑列?
似乎可行?

这个模型应该是无解了……换模型。
但是行列绑定不解决应该就没法用网络流模型。

打了快两个小时无果,只好先弃了……

10:00~10:40

签到后发现实际上就是求树上本质不同的树链个数,就是个裸的广义sam,直接上,写完调一下没问题。

但是因为没有造树数据的经验,造的树数据非常水,导致没有发现因为倒序搜索产生的空间问题,全RE了……

10:40~11:20

时间不是很足了,草草签到。

回想昨天做的期望题目,期望等于概率*对应的值(这里就是体力),于是大力了一发\(O(nmk)\)的dp,空间滚动一下(只注意了空间问题,没发现时间也炸了……),dp出经过k个障碍的路线数,合并一下就好了。

11:20~12:20

把T1建图时第二遍连边全新赋编号就能跟小数据拍过了……

然后罚坐+查ce。

result:

T1:50 T2:20 T3:40

只能说非常自闭,从来没这么自闭过,只能感叹自己又菜又笨,不会的算法写不出,会的算法打不对。

2.反思

T1:

为什么我不去写随机化而是冒险网络流呢……

这题有很好的退火性质,哪怕不退火暴力去rand也能卡边A掉。

网络流的思路是对的,把放最少棋子转化为全放好棋子后移除最多棋子,但是没有分析出来怎么解决选择一个点需要同时统计行列的影响的方法。

看了同机房J神的代码恍然大悟,还是这类模型见太少了,具体模型构建放在简要题解中。

T2:

赛后简单一改60,在J神的指引下再一改AC……

一个很显然的性质自己却忽略了(虽然考试时有想到):所有串都反转后本质不同子串数与反转前不变。

自己也不知道哪里来的自信,相信从叶子dfs的串的个数不超过20 * 1e5,实际上只需要一个菊花套菊花带上链的图就可以卡出来400 * 1e5的字符串个数……

一个原因是图论的数据跑的太少,没有经验;一个是思维太死板了,没有倒着考虑问题,没想到可以直接从根dfs加串。

T3:

倒是没爆炸,但是50分还是可以做的,注意到S最多变化logS次就一直等于1了,所以不需要计算出所有经过K个障碍的路线,这样的复杂度是\(O(nmlogS)\)的,总路线数可以直接组合数求出来。

3.简要题解

T1.

一句话题意:n行m列的的空棋盘,要求每行每列棋子数必须大于给定的值,有k个格子不能放棋子,判断无解或输出最少放多少棋子。

\(n,m\leq 100\)

无解不赘述,放满判一下。下面讨论有解的情况。

从数据范围就能看出来是网络流,考虑怎么建图。

因为网络流处理的多是小于等于的关系,所以把问题转化成一个全是棋子(除了k个格子)的棋盘最多拿走多少个棋子。

一个直接的想法是源向好格子连1,好格子向所在行、列连1,行/列向汇连n/m-c/r[i]-该行/列坏格子的数目。

但是会出现一个点被选中但不会同时流向行列,也就是流量偏大。(我一开始的思路就是这样被卡了……)

一个不正确的做法是源向好格子连边,好格子先向行连边,流到一个汇后再向好格子连边,同样操作向列和第二个汇连边,这样能水过一部分数据(我的做法),但显然不正确。

正解是统计出每行能放多少棋子,减去这行的目标作为源向行连的边的容量;列同理,连向汇;再对于好格子,把好格子的行列相连。

这样一个格子被选中的时候从行和列都有流量,就符合要求了(%%%JSY大神)。答案就是\(n * m-k-maxflow\)

T2.

一句话题意:求树上本质不同的树链个数,两个树链本质相同即长度相同,树链上每个点的度数相同。

\(n \leq 1e5\)

很裸的广义sam。

只需要直接从根一遍dfs就行了,注意必须dfs,因为实际上相当于把一个树链看做了一堆串的前缀,last指针的位置相同,才可以dfs去建sam。

伪正解:可以证明度数最多有450种左右的取值,空间复杂度最大8e7,但是根本跑不满,拿map存或离散化一下就好了。

真正解:树上SA,我不会,回头再说。

结论:一棵n个节点的树,最多只有\(sqrt(n)\)种不同的节点度数(可以出根号分治毒瘤题了)。

T3.

一句话题意:初始S点体力,只能向下和向右走,有K个障碍物,每撞到一个S/=2向上取整,求从<1,1>到<n,m>的期望体力。

\(n,m\leq 1e5,K \leq min(2e3,nm),s \leq 1e6\)

[HAOI2017]方案数很像,比他还简单点。

容易发现最多撞\(logS\)次障碍物后S就一直是1了,所以只需要计算撞\(logS\)次障碍物的路线有多少条,其他的体力都是1,可以直接计算。

\(f[i][j]\)表示前i个障碍物装了j个从<1,1>出发的路线条数。按照x,y偏序排序,易得转移方程。

\[f[i][j]=way(<1,1>,<p[i].x,p[i].y>)-(\sum_{k=1}^{i-1}[p[i].y>=p[k].y]f[k][j]*way(<p[i].x,p[i].y>,<p[k].x,p[k].y>))-(\sum_{k=1}^{j-1}f[i][k]) \]

way就是从一个点到另一个点的路径数。

在特殊点中再加入一个终点,做同样的转移,得到走到<n,m>的所有路径数。

因为至少要经过一次终点,答案从f[K+1][1]开始累加。

4.总结

本场比赛虽然成绩很惨,但是收获不小。

1.图论数据

不会造图论数据是很吃亏的,尤其是没有大样例的考试,就算有也需要造一些小数据对拍或测试极限数据。

尤其是树的数据,非常常考,需要学习怎么造,还要一些变种,比如有向图的内向外向树,基环树等,也要学一下。

//随机生成有节点度数限制的n个节点的树
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define mapa make_pair
#define fi first
#define se second 
int ran(int x){
	return (long long)rand()*rand()%x;
}
const int N=1e5+100;
int e[N],deg[N];
int main(){
	freopen("test.in","w",stdout);
	int n=100000,lim=20;
	srand(time(0));
	for(int i=1;i<n;i++){
		int fa=ran(i)+1;
		while(deg[fa]>=lim) fa=ran(i)+1;
		deg[fa]++;deg[i+1]++;
		printf("%d %d\n",fa,i+1);
	}
	return 0;
}

2.网络流模型

虽然做了那么多题,但网络流还是逢考必挂。

模板比自己名字记的还熟,主要是不会建模型。

今天已经很不错了,能想到大于号小于号的转化也是一个进步。

学到新的trick:对于一个二元组的双重限制可以转化为源流向一维,另一维流向汇,对每一个二元组链接两维,这样在源和汇处就可以做到对二元组的限制了。

模型不是模板,需要积累和熟练运用。

3.正难则反

T2既然从叶子做做不下去,那就不妨把所有路径都反过来,从根一遍扫完,问题本质没有变。

只要保证问题本质相同,有时候大胆的把要处理的东西反过来,或许能得到启发。

posted @ 2022-03-10 15:01  Displace  阅读(99)  评论(0)    收藏  举报