专栏文章

NOIP 8/12 题解

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miodiqb4
此快照首次捕获于
2025/12/02 17:26
3 个月前
此快照最后确认于
2025/12/02 17:26
3 个月前
查看原文
T1:
题意概述:
nn 次操作,有两种形式:
1.获得 xx 元或 00 元。
2.获得 yy 元或 [0,y2下取整][0,\frac{y}{2}下取整] 元的随机数。
问能不能通过 nn 次操作获得 mm 元。TT 组数据。
30pts:
枚举。
100pts:
数学题。
mm 的上界是 nynym>nym>ny 一定无解。考虑变化量,需要构造一种变化量,正好是 nymny-m。第二种操作的变化量是 [y2上取整,ny][\frac{y}{2}上取整,ny]
发现并出来的是一个连续区间 [y2上取整,y][\dfrac{y}{2}上取整,y]
考虑第一种操作,每次变化量为 yxy-x,所以 yxnymy-x|ny-m,且 n(yx)nymn(y-x) \ge ny-m
代码:
CPP
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
	ios::sync_with_stdio(0);
	int T;
	cin>>T;
	while(T--){
		ll n,x,y,m;
		cin>>n>>x>>y>>m;
		if(m>n*y){
			cout<<"No"<<'\n';
			continue;
		}
		if(n*y-m>=ceil(y/2)&&n*y-m<=n*y){
			cout<<"Yes"<<'\n';
			continue;
		}
		if((n*y-m)%(y-x)==0&&(n*(y-x)>n*y-m||n*(y-x)==n*y-m)){
			cout<<"Yes"<<'\n';
			continue;
		}
		cout<<"No"<<'\n';
	}
	return 0;
}
T2:
题意概述:
有一个 nnmm 边的图,原图每个点点权 aia_i,重新分配权值是 bib_i
(1)w(u,v),bubv<x ∀w(u,v),\dfrac{b_u}{b_v}<x
(2)ai=bi\sum a_i=\sum b_i
(3)1in,biaipq ∀1 \le i \le n,\dfrac{b_i}{a_i} \ge \dfrac{p}{q}.
xminx_{\min}
10pts:
送分。
30pts:
注意到,平均分配是最优的。
根节点要给自己留下 pq\dfrac{p}{q} 的权值,剩下每个节点分配出 1pqn1\dfrac{1-\dfrac{p}{q}}{n-1}。为什么要平均分配?如果不平均分配,那么就有一个节点大,一个节点小,则如果 nqpnq \ge p,那么 xx 会更大。所以答案就是 (n1)pqp(n-1) \dfrac{p}{q-p}
60pts:
最坏情况:有一节点无穷大,其他节点权值为 00。从 11nn 枚举一个点有权值,其他点没权值,建出一颗树。二分 xx,以每个点为根,做出每个点的深度,求 1xd\dfrac{1}{x^d} 求和,如果小于 1pq1-\dfrac{p}{q} 就可以。
时间复杂度 O(n2logn)O(n^2 \log n)
100pts:
ii 号点为根做出一颗 bfs 树,非树边最多出现在同层或相邻一层,求出最短路径即可。
优化:先跑 bfs 再二分。每个点在 bfs 树的深度时是一样的,所以我们只需要在二分之外再进行 bfs,时间复杂度 O(nm+n2loganseps)O(nm+n^2 \log \dfrac{ans}{eps})
代码:回去补。
T3:
两个 nn 个字符的字串 sstt,只能交换 ss 的两个相邻字符,求最少次数使得 s<ts<t
5pts:
CPP
cout<<-1;
15pts:
CPP
cout<<0;
20pts:
找到最小的 ii s.t. si<t1s_i<t_1ii 不存在就输出 1-1
60pts:
如何比较 sstt,一位一位比较。
sstt 的 LCP 是 ii,则 s1=t1,...,si=tis_1=t_1,...,s_i=t_isi+1<ti+1s_{i+1}<t_{i+1},第一步,枚举 LCP,LCP 中的字符怎么对应?一一对应,选最前面的。如果交换两个相邻字符是不优的。你可以飞快地一一对应完。每次扩展 LCP 时,就把 tt 中的对应位置移到 ii,问题就又转换为 BB 性质,我们可以从 i+1i+1 往后枚举就行了,时间复杂度为 O(n2)O(n^2)
100pts:
对每种字符开一个队列,每次扩展一格的时候,把 tit_i 的队列的队头取出,就可以建立一个关系,但是不能暴力计算,需要快速计算。
注意到 LCP 是 ss 中最前面的位置,只需要数出星号后有多少个位置往前移动?用树状数组维护,就相当于把 00 改成 11,求后缀和问题,就可以快速计算贡献。
时间复杂度 O(26nlogn)O(26n \log n)
注意到每次都要查一遍,对于 26 个队头,只需要确定最优的查一次就可以了,时间复杂度 O(26n+nlogn)O(26n+n \log n)
T4:
形式化题意:
nn 个点 rtrt 为根的图,求树的拓扑序的逆序对的个数和。
15pts:
暴力搜索。
25pts:
状压 DP。
dpi,Sdp_{i,S} 表示当前是 SS 状态,能到第 ii 个数的逆序对数量。
时间复杂度 O(2nn2)O(2^nn^2)
100pts:
如果 uuvv 的祖先,则 uu 在拓扑序上一定先于 vv,如果 u<vu<v 则贡献为 00,否则贡献为 11
一棵树的拓扑序数量就是 n!siz1×siz2×...sizn\dfrac{n!}{siz_1 \times siz_2 \times ... siz_n}。以概率考虑的时候,随机排律满足 ii 号点在它的子树的最前面概率是 1sizi\dfrac{1}{siz_i},最后概率乘积再乘上排列数 n!n! 就得到了数量。
问题转化为期望乘上拓扑序数量。
u,vu,v 为祖孙关系已经解决,那如果是非祖先关系呢?
不妨设 u<vu<v,设 cntu,vcnt_{u,v} 表示 u,vu,v 贡献的逆序对个数,aauulcalca 之间的(不包括 lcalca)点数,bblcalcavv 之间的(不包括 lcalca)点数。考虑只把 ulca(u,v)vu-lca(u,v)-v 这条链拉出来,最后加的点只可能是 uu 或者 vv,如果最后拉出来的是 uu,则求的就是 cntfau,vcnt_{fa_u,v},那么 uu 成为最后一个点的概率是什么?
fu,vf_{u,v} 代表只考虑 uu 子树和 vv 子树相互之间产生逆序对的概率之和。我们只需要算出 vv 子树中有多少个节点编号小于 uu 的。我们只需要预处理出 sumu,isum_{u,i},表示 uu 中有多少个点编号小于 ii 的,只需要将 uu 的子树染黑,vv 的子树染白,uu 就是黑色中最前面的,vv 就是白色中最前面的,只需要计算出黑色在最前面的概率。
同理,所以贡献就是 sumv,u×sizusizu+sizv+sumu,v×sizvsizu+sizvsum_{v,u} \times \dfrac{siz_u}{siz_u+siz_v}+sum_{u,v} \times \dfrac{siz_v}{siz_u+siz_v},所以转移方程就是 fu,v=(sumv,u+fson(u),v)×sizusizu+sizv+(sumu,v+fson(v),u)×sizvsizu+sizvf_{u,v}=(sum_{v,u}+\sum{f_{son(u),v}}) \times \dfrac{siz_u}{siz_u+siz_v}+(sum_{u,v}+\sum{f_{son(v),u}}) \times \dfrac{siz_v}{siz_u+siz_v}
答案就是枚举 lcalca,如果 u,vu,v 都是儿子的话,那么答案就是 fu,vf_{u,v} 之和,再加上祖孙关系的和。
为什么不能直接算概率?若 uu 的子树大,vv 的子树很小,那么概率就不是 12\dfrac{1}{2} 了。
时间复杂度 O(n2)O(n^2)

评论

0 条评论,欢迎与作者交流。

正在加载评论...