二轮前的做题记录1
这一轮主要做一下之前考试没改的杂题,提高思维水平和代码能力
1.数对子
题意:定义一个数对$(x,y)$是好的,当且仅当$x\le y$且$x\;xor\;y$二进制下有奇数个$1$,现在给定$n$个区间$[l_i,r_i]$,对每个$i(1\le i\le n)$求出区间内好的数对的个数
题解:首先可以发现答案一定是由二进制下$1$的个数为奇数的数个数乘以偶数的个数,考虑怎么去统计
我们发现$(0,1)(2,3)(4,5)...(2k,2k+1)$每相邻两个数都是由一个二进制下$1$的个数为奇数的数和一个偶数的数组成
剩下的问题就可以放到线段树上维护一下
2.逆序对
题意:给定一个由$[2,n]$的偶数组成的数组$b$,将所有$[1,n-1]$内的奇数按循序插入其中,求最少产生的逆序对的个数
题解:首先有一个简单的结论,即每个奇数的最优位置在数组$b$中是单调的,也就是说我们只需要单独考虑把每个奇数插在哪里即可
依次枚举奇数$i$,可以发现,当枚举到$i+2$时,若还放在$i$所在的位置上,那么只有$i+1$对位置会对答案产生影响
具体来说,若此时将$i+2$放在$i+1$的后面,那么就不会产生逆序对,但如果之前把某个奇数放在$i+1$之后则会产生一个逆序对
我们可以默认第$i$个位置本身会产生$i$的贡献,然后依次枚举每个奇数$i$,将$i-1$的位置$p$到$n$的整个区间都减去$2$
此时$i$点的最优答案就是$i/2+min(0,querymin(1,n/2))$,对$0$取$min$的意思是将$i$放在最前边,会和所有的小于$i$的数产生逆序对
然后用线段树维护一下这个过程即可
3.绕口令
题意:给出一个字符串,对每个$k(0\le k<n)$求是否存在一种方法使得割掉连续$k$个字符后剩下的序列不存在相邻两个相同的字符且首尾字符不同
题解:一个环删掉一段,剩下的也是连续的一段,所以考虑剩下的一段。如果原串中有相邻的相同字符,则在相同字符处切开把环切成若干段,剩下的显然是某个段的一部分。
判断某个段是否有长度为x的头尾不同的子段,相当于判断一个前缀和一个后缀是否相同,使用KMP或hash即可
这里稍微解释一下,如果某个段的长度为$k$的前缀和后缀相同,那么这一段一定无法在前缀和后缀上割下长度和为$k$的两段,具体证明画图即可理解
这样可以判断出哪些长度的串是可能被保留的,然后和串长做差得出的数也就是某个合法的$k$
4.亵渎
题意:你有一个可重集合$A$,$A$中的元素是正整数,当一个元素变为$0$时从集合中删除。 你可以花费$p$使一个元素$+1$,花费$q$使一个元素$−1$。 你有一次机会花费r使得集合中所有元素$−1$,若有元素因此被删除,则重复这个操作(不需要额外的花费)。 你的目标是最小化将集合变为空集的花费。
题解:如果不用亵渎就是暴力把所有的元素都砍成$0$,否则将其排成一个连续的序列然后最后用亵渎
可以用$dp$来处理这个过程,设$f[i][j]$表示将前$i$个砍成$1$到$j$的排列的最小代价,然后直接枚举元素转移即可
5.世界杯
题意:假设在世界杯决赛前,有$n$个人参与了赌博。第$i$个人认为法国队赢的概率是$p[i]$,克罗地亚队赢的概率是$1−p[i]$。对于每一只球队,如果根据博彩公司给出的赔率第$i$个人的期望收益非负,则他会给这只球队下注$a[i]$元(设赔率为$x$,某人下注了$y$元,如果他赢了可以返还$x∗y$元,他输了则会返还$0$元。不论输赢,下注的钱均不返还)。如果两只球队期望收益均非负,则他会给两只球队各下注$a[i]$元。
现在博彩公司要决定法国队和克罗地亚队的赔率,使得在自身收益最小的胜负情况下的收益最大。
题解:
设法国队赔率为$x$,克罗地亚队赔率为$y$
当且仅当$x>=1/p[i]$时第$i$个人会下注法国队,当且仅当$y>=1/(1-p[i])$时第$i$个人会下注克罗地亚队
把所有人按照$p[i]$从大到小排序,则下注法国队的是一个前缀,下注克罗地亚队的是一个后缀
$x$越大,下注法国队的越大,博彩公司在法国队赢时赔得越多,所以需要增加$y$使更多人下注克罗地亚队,即$y$随$x$增加而增加
枚举$x$,滑动$y$使得最小收益最大即可
6.配对
题意:给定一棵$n$个点的边有长度的无根树,小A的班里一共有$m$个男生和$m$个女生,他们各自会等概率出现在树上$n$个点中的某一个,(注意同一个点上可能会出现多个人)。
然后小 A 会将他们配对成$m$对男女,设$dis_i$是第$i$对男女在树上的最短距离,小A会选择使得 $\sum_{i=1}^m dis_i$最大的配对方案。
现在小$A$想知道,他选择的配对方案中$\sum_{i=1}^m dis_i$的期望,由于答案可能过大,你只需要输出答案$∗n^{2m}$后对$10^9+7$取模的值,这个值显然是一个整数
题解:可以发现最优方案一定是让所有边尽可能多的被经过,而一条边被经过的次数即为它连接的两个联通$x,y$的人数的较小值$min(s_x,s_y)$,原因是人数较少的一边一定无论是男生或者女生都会比另一个联通块少。然后就可以枚举每一条边,再枚举左右两个联通块内的人数,用组合数简单计算一下即可。
7.数组
题意:对一个数列的每个位置求前缀最大值的和
题解:学习了一种全新的线段树,每个节点维护一下当前区间内的答案和区间最大值。向上合并的时候可以分情况讨论:
1.左区间的最大值大于右区间的最大值,那么右区间一定是被左区间限制住,所以右区间答案为$sz*mx[ls]$,然后递归计算左区间的答案
2.左区间的最大值小于右区间的最大值,那么左区间会对右区间的部分位置产生限制,递归进去求出那些位置对答案的贡献即可
还是放一下代码吧
1 struct Segment{ 2 int Ri[M<<2];ll ans[M<<2]; 3 ll calc(int node,int l,int r,int v) { 4 if(l==r) return max(Ri[node],v); 5 int mid=(l+r)>>1; 6 if(Ri[ls]<v) return 1ll*(mid-l+1)*v+calc(rs,mid+1,r,v);//无法对左边有任何影响但有可能对右边有影响 7 else return ans[node]-ans[ls]+calc(ls,l,mid,v);//对部分左边产生影响但不可能对右边有影响(左边已经有控制右边最大值的点了) 8 } 9 void update(int node,int l,int r) { 10 int mid=(l+r)>>1; 11 if(Ri[ls]>=Ri[rs]) Ri[node]=Ri[ls],ans[node]=ans[ls]+1ll*(r-mid)*Ri[ls]; 12 else Ri[node]=Ri[rs],ans[node]=ans[ls]+calc(rs,mid+1,r,Ri[ls]); 13 } 14 void change(int node,int l,int r,int x,int v) { 15 if(l==r) {ans[node]=Ri[node]=v;return;} 16 int mid=(l+r)>>1; 17 if(x<=mid) change(ls,l,mid,x,v); 18 else change(rs,mid+1,r,x,v); 19 update(node,l,r); 20 } 21 void build(int node,int l,int r) { 22 if(l==r) {ans[node]=Ri[node]=lst[l];return;} 23 int mid=(l+r)>>1; 24 build(ls,l,mid);build(rs,mid+1,r); 25 update(node,l,r); 26 } 27 }T;
8.友谊巨轮
题意:
这个地球上一共有$n$个人,他们之间会互相发消息。在每个时刻,$a$与$b$之间互相发了$c$条消息。对于每个人,他友谊的巨轮为最近$m$个时刻里与他发消息最多的人,如果有多个发消息最多的人,那么巨轮为这里面最近发的人。如果这个人在最近$m$个时刻里面没有与任何人发过消息,那么它没有友谊的巨轮。
在这个题目里面,我们设定一个时刻只有某两个人之间互相发了$c$条消息。
你获得了上帝视角,知道了每个时刻哪两个人发了消息。你经常会发现Alice和Bob发完晚安之后,又和Charlie聊一整晚。Bob的巨轮是Alice,但是Alice的巨轮却是Charlie。你想知道,每个时刻发完消息之后,有多少的人的巨轮是单向的,即他的巨轮的巨轮不是他。
题解:乱搞题,每个人的巨轮可以用线段树维护出来,然后每次修改直接更新答案即可。
9.花园
题意:给定一张$n$个点的图,有$m$条边,每条边有一个魅力值。每个点上都有一个人,每秒会向魅力值最大的边移动,若刚才是从这条边过来的则向次大值移动(若没有次大值还是向最大值移动)。
给定$Q$个$K$,每次询问$K$秒后有多少人会到达点$P$($P$是定值).
题解:预处理出来每个点到$P$点的距离,按$P$点是否在环上分类讨论即可。注意细节。
10.构解巨树
题意:你有一棵$n$个点树$T$,然后你把它复制了$m$遍,然后在这$m$棵树之间又加了$m−1$条边,变成了一棵新的有$nm$个点的巨树$T2$。求$T2$中所有点对的距离和
题解:很有趣的一道题。把边分为原树的边和加入的边考虑。对于加入的边,直接$DP$求一下即可。而对于树边,我们可以把树分为$m$颗来做。每条边的贡献就是其连接的两块联通块的大小的乘积。每次修改相当于在某个点上挂一坨东西,从而影响它到根的路径上的子树和。所以用链剖来维护一下子树和和子树的平方和即可
11.机场
题意:给定一个$n$个点的树,每个点有一个权值$wi$,找到一个点$x$,使得$\sum_{i=1}^n w_i dis(x,i)^{\frac{3}{2}}$最小。
题解:我们设$g(x)=\sum_{i=1}^n w_i dis(x,i)^{\frac{3}{2}}$,不难发现这是个凸函数。然后考虑一个点$u$,一定最多只有一个儿子使得从$u$向该儿子$v$的方向走去时答案会变小。考虑边$(u,v)$上一个距离$u$长度为$x$的点,那么在该点的答案即为:
$f(x)=\sum_{i\in u}w_i{(dis(u,i)+x)}^{\frac{3}{2}}+\sum_{i\in v}w_i{(dis(u,i)-x)}^{\frac{3}{2}}$
求导得:
$f(x)'=\sum_{i\in u}w_i \sqrt{dis(u,i)+x}-\sum_{i\in v}w_i \sqrt{dis(u,i)-x}$
由于$g(x)$是凸函数,所以最多存在一个$v$使得$f'(0)<0$,所以我们运用点分治寻找关键点的套路来做了
只需要在每个分治中心暴力计算答案以及求出所有儿子的$f'(0)$,然后找一个最小的向下分治即可
12.传送
题意:给定一棵基环内向树,调整一些边使得每个点走$k$步后都能到$1$,求最少的调整次数。
题解:首先将$1$连向本身,这样就保证所有点到$1$的距离小于$k$时的正确性。然后自底向上贪心,若一个点的子树内有到$1$距离$==k$的点就将这个点挂在$1$的下面
13.归来
题意:有一个初始由$A,B,C,D$组成的字符串,每次支持交换相邻两个字符,或者可以选取字符串中的一个子串$S1$转换成等长子串$S2$($S1,S2$题目给出且均由$A,B,C,D$组成)。你可以确定一个初始状态,使得他能变换成的不同字串数目最多。
题解:由于存在交换位置的操作,所以我们不需要考虑字串中字符的顺序,而只需考虑每种字符的数量,然后以这个为状态跑$tarjan$最长路即可