啊啊啊啊啊啊第四天考的是我最不擅长的图论……整个人都斯巴达了
//另外不得不吐槽下午的上课讲的都是网络流……难道是出题人觉得图论里除了网络流以外的其他算法都没有人权图样图森破?
愚蠢的算法(clumsy)
时限:1s
输入文件:clumsy.in
输出文件:clumsy.out
问题描述
对于一个1~n的排列{p1,p2,…,pn},将pi和pj交换,需要的代价为2*|i-j|-1,记f(p)表示通过交换将排列p变成从小到大的排列,即{1,2,3…,n}的最小代价。一个愚蠢的算法是用g(p)=Σmax(0, i-pi)来估算f(p)。给出1~n的排列的前m个元素,求有多少个排列p满足条件f(p)=g(p)。
输入格式
输入n和m,表示1~n的排列,以及确定了前m个数。
接下来一行包含m个数,表示排列中确定的前m个数。
输出格式
输出一行,表示有多少个排列满足条件,输出答案mod 10^9+7。
样例输入1
3 0
样例输出 1
5
样例输入 2
5 2
1 4
样例输出 2
3
数据规模
对于20%的数据,n≤10
对于50%的数据,n≤200
对于100%的数据,n≤2000,m≤n
原来在考场上看题目半天没想到怎么算f[p]。
然后发现对于每次交换,因为代价是2 * abs(i - j) - 1,所以显然相邻的两个数交换代价是1。然后再仔细观察发现实际上p[i]和p[i+1]交换、p[i+1]和p[i+2]交换……p[j-1]和p[j]交换,然后p[j-1]和p[j-2]交换……p[i+1]和p[i]交换,这样两两相邻的交换实际上就实现了交换p[i]、p[j]的操作。而这样刚好要交换2 * abs(i - j) - 1次,所以实际上交换只要考虑相邻交换就可以了。所以f[p]就是一个全排列中一项p中的逆序对个数。(这一点我在考场上就根本没有想到)
那么接下来考虑何时f[p]=g[p]。
假设当前做了 i 个点,且满足f[p]=g[p]。那么接下来应该在某个位置插入p[i+1]。考虑这样对f[p]、g[p]的影响:
如果直接扔尾巴后面,那么显然g[ p' ] = g[ p ],同时逆序对个数不变,所以f[ p' ] = f[ p ]。答案直接更新就可以了
如果扔到 j 的位置,那么逆序对加了i - j + 1个,此时g[ p' ]也需要增加i - j + 1。但是在 j 前面的k,max(0 , k - p[k])是不受j的影响的。那这样就要求在j后面的所有k>j,有max(0 , (k+1) - p[k])比max(0 , k - p[k])大1。
然后是dp。记f[i,j]表示前i个元素的排列中,最后j个元素pk满足k-pk≥0的方案数,
f[i , j] = f[i-1 , j-1] + Σf[i-1 , k],k>=j。
f[1 , 1] = 1。
即
f[i , j] = f[i , j-1] + f[i-1 , j-1]。
f[1 , 1] = 1;
题目中还有给定的前m个数,那么对于固定的数字,在转移的时候只用这个位置转移就可以。对于未知的数字,因为有一些数的位置已经确定,所以可以知道i前面至少有几个数,那么i只能放在后面。
圆桌会议(conference)
时限:5s
输入文件:conference.in
输出文件:conference.out
问题描述
有n组人要一起开一个圆桌会议(编号为0~n-1),会议的圆桌上有m个位置(编号为0~m-1)。每个组有ai个人,他们需要被安排在(li,(li+1)%m,(li+2)%m,…,ri)的座位范围内。每个座位只能安排一个人就坐,并且每个人都需要被安排一个座位。现在你需要判断是否存在满足条件的座位安排。
输入格式
输入包含不超过10组数据。
第一行有一个数字T,表示数据组数。
接下来有T组数据,每组数据第一行包含两个数n,m,表示有多少组的人与圆桌的位置数。
每组数据接下来包含n行,每行包含3个数li,ri,ai。
输出格式
对于每组数据,输出”Yes”或”No”,表示是否存在符合条件的安排。
样例输入
2
2 4
0 1 2
1 2 2
2 3
2 0 2
1 1 1
样例输出
No
Yes
数据规模
对于30%的数据,n≤1000,m≤100000
对于100%的数据,T≤10,其中有不超过3组的数据范围为n≤105,m≤109,其余与30%数据范围相同
好坑的一道题……首先很容易看出这是个二分图,那么可以用网络流模型。然而n*m的边数不是我们能接受的,即使是离散化之后也有2*n=20w的点,就是400e的边。这显然不能接受。
正解是用了一个叫Hall定理的
注意到这只是一个判定性问题,不需要输出最多多少个人之类的。而且建边也是连续的区间,所以网络流是有写多余的。
Hall定理是:如果对于二分图的左部的任意一个大小为n子集,在右边总有大小>=n的集合能和它联通,那么这个二分图一定有完全匹配。
首先断环成链,对于任意区间[l , r],令len = r - l + 1,把所有包括在[l , r]的询问[li , ri]提取出来并把a[i]求和,如果Σa[i]>len,则一定无解。
显然询问[l , r]中当l=li或者r=ri时才是有用的,因为如果l=li时成立,那么l<li时也一定成立。r同理。
考虑当sum=Σa[i]>len时无解,由len=r-l+1移项得:sum+l-1>r。所以我们只要判定这个式子成立,原式就无解。
那么首先将所有询问按r升序排列,用一个线段树维护key=sum+l-1。对于区间[1 , li]的每一个l,询问[l , ri]的sum都要增加ai,所以用区间操作搞掉就好了
判断的时候 只要找[1 , ri]的maxkey,如果maxkey>ri就无解了
最短路(shortest)
时限:1s
输入文件:shortest.in
输出文件:shortest.out
题目描述
给出一个n个点m条边的无向图,n个点的编号从1~n,定义源点为1。定义最短路树如下:从源点1经过边集T到任意一点i有且仅有一条路径,且这条路径是整个图1到i的最短路径,边集T构成最短路树。
给出最短路树,求对于除了源点1外的每个点i,求最短路,要求不经过给出的最短路树上的1到i的路径的最后一条边。
输入格式
第一行包含两个数n和m,表示图中有n个点和m条边。
接下来m行,每行有四个数ai,bi,li,ti,表示图中第i条边连接ai和bi权值为li,ti为1表示这条边是最短路树上的边,ti为0表示不是最短路树上的边。
输出格式
输出n-1个数,第i个数表示从1到i+1的要求的最短路。无法到达输出-1。
样例输入
5 9
3 1 3 1
1 4 2 1
2 1 6 0
2 3 4 0
5 2 3 0
3 2 2 1
5 3 1 1
3 5 2 0
4 5 4 0
样例输出
6 7 8 5
数据规模
对于30%的数据,n≤100,m≤2000
对于100%的数据,n≤4000,m≤100000,1≤li≤100000
lwher:首先题意是给你最短路树,问所有点不经过最后一条树边的最短路。
首先注意到从1到x的最短路要不经过最后一条非树边,一定是走到树边的某一节点然后绕一圈到达x。
然后在树边上加非树边的过程会产生环,那么要统计加入的边对其他点最短路的影响,用剖分搞
所以树链剖分。
akf:更快的是采用一种类似最小生成树的方法:把非树边sort,然后加入树边中。每条非树边更新过一个联通块后不可能用相同的边再更新了,所以并查集搞定