2025-10-8模拟测验
结果:\(\texttt{90 + 100 + 80 + 90 = 360 pts, rank 2}\)。
T1 HYH的线段
算法:计算几何(?)。
描述
HYH 第一类平面是一个无穷大的平面,另外 HYH 同学在平面上作出两条线段 \(AB\) 和 \(CD\)。
HYH 同学发现,两条线段可能相交,也可能不相交。HYH 同学觉得好神奇哦!所以他想要知道,两条线段的距离是多少。
线段 \(AB\) 和 \(CD\) 的距离定义为,线段 \(AB\) 上的点 \(P\) 和线段 \(CD\) 上的点 \(Q\)(均可与线段端点重合)的连线 \(PQ\) 长度的最小值。
现在给定两条线段的端点坐标,要求计算线段的距离。
输入
输入只有四行,每行两个整数(在 \([-100,100]\) 内),分别表示点 \(A,B,C,D\) 的坐标。
输出
输出只有一个四位小数,表示线段 \(AB\) 和 \(CD\) 的距离。
样例
共 \(1\) 组,不包含大样例。
样例 \(1\) 输入
0 5
0 4
-1 0
1 0
样例 \(1\) 输出
4.0000
题解
首先,对于线段相交的情况,直接输出 \(0.0000\) 即可。
反之,我们写一个函数,用于求出点到线段的最小距离。显然,这个距离要么是垂线(如果可以),要么与某个端点相连。
而不相交的情况下,我们只需要对于两条线段的四个端点分别计算到另一条线段的距离,然后四个距离取最小值即可。
但是垂线、平行等情况有可能出现除 \(0\) 导致 RE,所以要大力分讨一下。
#include<bits/stdc++.h>
#define y1 y_1
using namespace std;
inline double dis(double x1, double y1, double x2, double y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
inline double dtoxd(double x1, double y1, double xax1, double xay1, double xbx1, double xby1){
if(xax1 == xbx1){
if(min(xay1, xby1) <= y1 && y1 <= max(xay1, xby1)){
return fabs(xax1 - x1);
}
return min(dis(x1, y1, xax1, xay1), dis(x1, y1, xbx1, xby1));
}else{
double k = (xay1 - xby1) / (xax1 - xbx1);
double b = xay1 - k * xax1;
if(!k){
if(min(xax1, xbx1) <= x1 && x1 <= max(xax1, xbx1)){
return fabs(xay1 - y1);
}
return min(dis(x1, y1, xax1, xay1), dis(x1, y1, xbx1, xby1));
}else{
double czk = -1.0 / k;
double czb = y1 - czk * x1;
double x0 = (b-czb) / (czk-k);
double y0 = k * x0 + b;
if(min(xay1, xby1) <= y0 && y0 <= max(xay1, xby1)){
return dis(x1, y1, x0, y0);
}
}
}
return min(dis(x1, y1, xax1, xay1), dis(x1, y1, xbx1, xby1));
}
double a1x, a1y, b1x, b1y, c1x, c1y, d1x, d1y;
inline double fab(double x){
if(a1x == b1x) return 101;
double k = (a1y - b1y) / (a1x - b1x);
double b = a1y - k * a1x;
return k * x + b;
}
inline double fcd(double x){
if(c1x == d1x) return 101;
double k = (c1y - d1y) / (c1x - d1x);
double b = c1y - k * c1x;
return k * x + b;
}
inline bool cross(){
// cout << a1x << " " << b1x << endl;
if(a1x == b1x){
return min(a1y, b1y) <= fcd(a1x) && fcd(a1x) <= max(a1y, b1y);
}
// cout << "Here1";
// cout<<fab(b1x) - fcd(b1x);exit(0);
double cross1 = (fab(a1x) - fcd(a1x)) * (fab(b1x) - fcd(b1x));
double cross2 = (fab(c1x) - fcd(c1x)) * (fab(d1x) - fcd(d1x));
// cout << cross1 << " " << cross2 << endl;
// if(!cross1 || ! cross2){
// // cout << "duandian" << endl;
// return true;
// }
return cross1 <= 0 && cross2 <= 0;
}
// inline void Print(){
// cout << a1x << " " << a1y << endl;
// cout << b1x << " " << b1y << endl;
// cout << c1x << " " << c1y << endl;
// cout << d1x << " " << d1y << endl;
// return;
// }
signed main(){
// freopen("segment.in", "r", stdin);
// freopen("segment.out", "w", stdout);
cin >> a1x >> a1y;
cin >> b1x >> b1y;
cin >> c1x >> c1y;
cin >> d1x >> d1y;
// cout << "kkkkk";exit(0);
if(a1x == b1x && c1x == d1x){
if(min(a1y, b1y) <= c1y && c1y <= max(a1y, b1y)){
cout << fixed << setprecision(4) << fabs(a1x-c1x) << '\n';
}else if(min(a1y, b1y) <= d1y && d1y <= max(a1y, b1y)){
cout << fixed << setprecision(4) << fabs(a1x-c1x) << '\n';
}else{
// Print();
// cout << dis(1, 4, -1, 3) << endl;exit(0);
double ans = min({
dis(a1x, a1y, c1x, c1y) ,
dis(a1x, a1y, d1x, d1y) ,
dis(b1x, b1y, c1x, c1y) ,
dis(b1x, b1y, d1x, d1y)});
cout << fixed << setprecision(4) << ans << '\n';
}
return 0;
}
if(c1x == d1x){
swap(a1x, c1x), swap(a1y, c1y);
swap(b1x, d1x), swap(b1y, d1y);
}
if(cross()){
cout << "0.0000" << '\n';
return 0;
}
// Print();
// cout << dtoxd(a1x, a1y, c1x, c1y, d1x, d1y) << endl;
// cout << dtoxd(b1x, b1y, c1x, c1y, d1x, d1y) << endl;
// cout << dtoxd(c1x, c1y, a1x, a1y, b1x, b1y) << endl;
// cout << dtoxd(d1x, d1y, a1x, a1y, b1x, b1y) << endl;
// cout << "jbjbjb";
double ans = min({
dtoxd(a1x, a1y, c1x, c1y, d1x, d1y) ,
dtoxd(b1x, b1y, c1x, c1y, d1x, d1y) ,
dtoxd(c1x, c1y, a1x, a1y, b1x, b1y) ,
dtoxd(d1x, d1y, a1x, a1y, b1x, b1y)});
cout << fixed << setprecision(4) << ans << '\n';
return 0;
}
T2 HYH的逻辑电路
算法:树形 DP。
描述
HYH 逻辑电路是 HYH 最新发明的新型逻辑电路。
这个电路由三大元件组成,“And”(与)元件,“Or”(或)元件,“Xor”(异或)元件。每个元件都有两个元件通过电路向它输入信号,元件进行相应的处理后输出到下一个元件上,如图:

(红点为元件,蓝线为电路)
其中,信号只有两种:0和1,每个元件对信号进行的操作与普通逻辑运行规则相同:
And:与,都为1信号输出1,其他情况输出0.
Or:或,两个信号中至少有一个1输出1,其他情况输出0。
Xor:异或,两个信号相同输出0,否则输出1。
HYH 逻辑电路是一个设计好的逻辑电路,由用户输入一些信号,经过囧囧,啊不是,种种处理,就能在唯一的输出端上得到一个信号。可是,大部分用户发现,HYH 逻辑电路无法对他们的信号得到他们想要的结果(?),于是准备投诉 HYH。HYH 很怕,所以他决定篡改最少数量的初始信号(越多越容易被发现嘛),使输出端信号改变。HYH 的标程不用说又是萝莉控语言的,请您帮他设计出一个能在普通电脑上运行的程序。
输入
首先第一行是两个数 \(n\) 和 \(m\),表示有 \(n\) 个元件,其中 \(m\) 个元件没有输入信号。元件被编号为 \(1 \sim n\)。
接下来的 \(n\) 行,第 \(i\) 行表示 \(i\) 号元件的情况,以 x y z a 表示输入信号的是 \(x\) 和 \(y\) 号元件,输出信号到 \(z\) 号元件,元件的种类是 \(a\)。假如没有输入或没有输出的元件则以 \(0\) 表示。
种类以 \(1 \sim 3\) 表示,\(1\)表示 And,\(2\) 表示 Or,\(3\) 表示 Xor。
再接下来是 \(m\) 行,每行以 \(x,y\) 表示一个无输入信号的元件 \(x\) 的初始信号为 \(y\)。不用检验数据正确与否,信号保证只有 \(0,1\) 两种可能。
输出
输出只有一行,表示改变输出端信号最少要改变多少个初始元件。
样例
共 \(1\) 组,不包含大样例。
样例 \(1\) 输入
7 4
2 3 0 3
4 5 1 2
6 7 1 1
0 0 2 3
0 0 2 3
0 0 3 3
0 0 3 3
4 0
5 1
6 1
7 0
样例 \(1\) 输出
1
题解
我们令 \(dp_{u,0/1}\) 表示把 \(u\) 的输出值修改为 \(0/1\) 至少需要修改几个初始值。转移的时候大力分讨即可。时间复杂度 \(\mathcal{O}(n)\)。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
const int N = 200005;
int n, m, root, ls[N], rs[N], type[N];
bool chu[N], haschu[N];
int dp[N][2];
inline void dfs1(int u){
if(!u || haschu[u]) return;
dfs1(ls[u]), dfs1(rs[u]);
if(type[u] == 1){
chu[u] = chu[ls[u]] & chu[rs[u]];
}else if(type[u] == 2){
chu[u] = chu[ls[u]] | chu[rs[u]];
}else{
chu[u] = chu[ls[u]] ^ chu[rs[u]];
}
return;
}
inline void dfs2(int u){
if(!u) return;
if(haschu[u]){
dp[u][chu[u]] = 0, dp[u][!chu[u]] = 1;
return;
}
dfs2(ls[u]), dfs2(rs[u]);
if(type[u] == 1){
dp[u][1] = dp[ls[u]][1] + dp[rs[u]][1];
dp[u][0] = min({
dp[ls[u]][0] + dp[rs[u]][0],
dp[ls[u]][0] + dp[rs[u]][1],
dp[ls[u]][1] + dp[rs[u]][0]}
);
}else if(type[u] == 2){
dp[u][0] = dp[ls[u]][0] + dp[rs[u]][0];
dp[u][1] = min({
dp[ls[u]][1] + dp[rs[u]][1],
dp[ls[u]][1] + dp[rs[u]][0],
dp[ls[u]][0] + dp[rs[u]][1]}
);
}else{
dp[u][0] = min(
dp[ls[u]][0] + dp[rs[u]][0]
,
dp[ls[u]][1] + dp[rs[u]][1]
);
dp[u][1] = min(
dp[ls[u]][1] + dp[rs[u]][0]
,
dp[ls[u]][0] + dp[rs[u]][1]
);
}
return;
}
signed main(){
// freopen("logical.in", "r", stdin);
// freopen("logical.out", "w", stdout);
n = read(), m = read();
for(int i = 1; i <= n; i++){
ls[i] = read(), rs[i] = read();
int fa = read();
if(!fa) root = i;
type[i] = read();
}
for(int i = 1; i <= m; i++){
int u = read();
chu[u] = read(), haschu[u] = true;
}
dfs1(root);
// for(int i = 1; i <= n; i++) cout << chu[i] << ' ';
dfs2(root);
cout << dp[root][!chu[root]] << '\n';
return 0;
}
T3 HYH的查找树
算法:图论、dfs 序。
描述
我们假定 HYH 查找树是(以下简称 HST,HYH's Search Tree)一颗最多有 \(n\) 个节点的有根树。
HYH 希望你能为 HST 设计一个程序,能够快速地得到某两个给定节点的关系。具体地说,希望你能返回某个节点是否为另外一个节点的祖先。
HST的描述方式比较奇怪:节点按层次从 \(1\) 编号到 \(n\),编号为 \(1\) 的节点总是 HST 的根。每个节点的儿子个数以一个函数 \(s(x) = ( s5 \times x ^ 4 + s4 \times x ^ 3 + s3 \times x ^ 2 + s2 \times x + s1 ) \bmod p\) 给出(后面若干个节点可选择的节点个数(即编号已经大于 \(n\))不足 \(s(x)\)个,则它的儿子数为剩下的节点个数)。
举例来说,一颗 \(5\) 个节点的 HST 的 \(s[1 \sim 5]=(1,2,3,4,5)\),则 HST 的形态如图。

特别地,如果某时无法继续扩展,则剩下的节点作废,比如说 \(1\) 号节点有 \(0\) 个儿子,那么整棵树只有一个节点。
HYH 同学希望你回答 \(q\) 个询问,第 \(i\) 个询问以数对 \(( x , y ) = ( (( a3 \times i ^ 2 + a2 \times i + a1 ) \bmod n) + 1 , (( b3 \times i ^ 2 + b2 \times i + b1 ) \bmod n) + 1 )\) 的形式给出,表示询问编号为 \(x\) 的节点是否编号为 \(y\) 的节点的祖先。
输入
第一行,两个整数 \(n\) 和 \(q\)(\(1 \leq n \leq 10^6,1 \leq q \leq 10^5\))。
第二行,\(6\) 个整数,表示 \(s5、s4、s3、s2、s1\) 和 \(p\)。
第三行,\(6\) 个整数,表示 \(a3、a2、a1、b3、b2\) 和 \(b1\)。
输出
输出一个整数,表示一共有多少对询问 \((x,y)\) 使节点 \(x\) 是节点 \(y\) 的祖先。
样例
共 \(1\) 组,不包含大样例。
样例 \(1\) 输入
5 1
0 0 0 1 0 10000
0 0 1 0 0 4
样例 \(1\) 输出
1
题解
首先,我们可以根据题意暴力建树。
然后我们对树进行 dfs。这里有一个结论:假设 \(in_u\) 表示访问到 \(u\) 节点的时间,\(out_u\) 表示离开 \(u\) 的时间。那么当 \(in_u < in_v\) 且 \(out_u > out_v\) 时,\(u\) 是 \(v\) 的祖先。
于是 dfs 的时候维护时间戳就做完了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n, q, s[6], p;
inline int S(int x){
return (((((s[5] % p * x % p * x % p * x % p * x % p +
s[4] % p * x % p * x % p * x % p) % p +
s[3] % p * x % p * x % p) % p +
s[2] % p * x % p) % p) % p +
s[1] % p) % p;
}
int fa[1000005], in[1000005], out[1000005];
vector<int> e[1000005];
int tot = 0;
inline void dfs(int u){
in[u] = ++tot;
for(auto v : e[u]) dfs(v);
out[u] = ++tot;
return;
}
signed main(){
// freopen("tree.in", "r", stdin);
// freopen("tree.out", "w", stdout);
cin >> n >> q;
for(int i = 5; i >= 1; i--) cin >> s[i];
cin >> p;
// for(int i = 1; i <= n; i++) cout << S(i) << " ";
// cout << endl;
int cnt = 1; fa[1] = -1;
for(int i = 1; i <= n && cnt <= n; i++){
if(!fa[i]) break;
int neww = min(S(i), n - cnt);
for(int j = 1; j <= neww; j++) fa[++cnt] = i;
}
// cout << cnt << endl;return 0;
int nn = n;
n = cnt;
// for(int i = 1; i <= n; i++) cout << fa[i] << " ";
// cout << endl;
for(int i = 2; i <= n; i++) e[fa[i]].push_back(i);
dfs(1);
// for(int i = 1; i <= n; i++) cout << in[i] << " ";
// cout << endl;
// for(int i = 1; i <= n; i++) cout << out[i] << " ";
int a3, a2, a1, b3, b2, b1;
cin >> a3 >> a2 >> a1 >> b3 >> b2 >> b1;
int ans = 0;
for(int i = 1; i <= q; i++){
int mod = nn;
int x = ((a3 % mod * i % mod * i % mod +
a2 % mod * i % mod) % mod +
a1 % mod
) % mod + 1;
int y = ((b3 % mod * i % mod * i % mod +
b2 % mod * i % mod) % mod +
b1 % mod
) % mod + 1;
// cout << x << " " << y << endl;
if(1 <= x && x <= n && 1 <= y && y <= n){
if(in[x] < in[y] && out[x] > out[y]){
// cout << x << " " << y << endl;
ans++;
}
}
}
cout << ans << '\n';
return 0;
}
T4 HYH的歌词
纯模拟。。。
随便放个题面和 \(90\) 分的代码,不修 \(\LaTeX\) 了。
描述
题目背景
HYH同学喜欢听歌,尤其喜欢看歌词……由于个人问题,他开始对LRC歌词进行研究……
题目描述
众所周知地,听音乐想看歌词可以安装《千千静听》或者Winamp+歌词显示插件等等软件实现。而现在的歌词,大多是以lrc为后缀名的歌词文件。
HYH同学最近在使用此类软件的时候,萌发了想制作一个同类软件的念头。可是由于他只有囧力没有编程力,所以只好靠你了。
附Lrc格式说明:
LRC 歌词是一种包含着“[:]”形式的“标签(tag)”的、基于纯文本的歌词专用格式。最早由郭祥祥先生(Djohan)提出并在其程序中得到应用。这种歌词文件既可以用来实现卡拉OK功能(需要专门程序),又能以普通的文字处理软件查看、编辑。当然,实际操作时通常是用专门的LRC歌词编辑软件进行高效编辑的。以下具体介绍LRC格式中的“标签”。
时间标签(Time-tag)
形式为"[mm:ss]"或"[mm:ss.fff]"(分钟数:秒数)。数字须为非负整数,比如"[12:34.5]"是有效的,而"[0x0C:-34.5]"无效。
它可以位于某行歌词中的任意位置。一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。根据这些时间标签,用户端程序会按顺序依次高亮显示歌词,从而实现卡拉OK功能。
标识标签(ID-tags)
其格式为"[标识名:值]"。大小写等价。以下是预定义的标签。
[ar:艺人名]
[ti:曲名]
[al:专辑名]
[by:编者(指编辑LRC歌词的人)]
[offset:时间补偿值] 其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。
以下列出了开发支持LRC格式的软件时应遵守的一些标准。
无论是否在行首,行内凡具有“[:]”形式的都应认为是标签。(注意:其中的冒号并非全角字符“:”)
凡是标签都不应显示。
凡是标签,且被冒号分隔的两部分都为非负数,则应认为是时间标签。因此,对于非标准形式(非“[mm:ss]”)的时间标签也应能识别(如“[0:0]”)。
凡是标签,且非时间标签的,应认为是标识标签。
标识名中大小写等价。
为了向后兼容,应对未定义的新标签作忽略处理。另应对标识标签后的同一行内容作忽略处理。
应允许一行中存在多个标签,并能正确处理。为简化本题,一行中不会同时存在标识标签和时间标签。
应能正确处理未排序的标签。
注意:为简化本题,数据保证正确,不存在未定义标签等等格式问题。并且保证时间没有相同的。
输入
第一行一个整数n,表示输入的行数。
接下来有n行,每行有一个字符串,整个输入文件是一个lrc文件。
字符串长度有可能超过255,请注意处理。
时间标签保证不超过100个。
输出
输出歌词显示时的结果(即按照时间标签排序好的歌词)
样例
输入
3
[ar:HYH]
[00:01][00:03]Oh Yeah~
[00:02]HYH is A BIGCOW!
输出
Oh Yeah~
HYH is A BIGCOW!
Oh Yeah~
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
string s, geci[60005];
vector<string> tag[60005];
double FENZHONG, MIAOSHU;
inline bool istimetag(string str){
if(str.length() < 3) return false;
if(str[0] != '[' || str[str.length()-1] != ']') return false;
int mhpos = -1;
for(int i = 0; i < str.size(); i++){
if(str[i] == ':'){
mhpos = i;
}
}
if(mhpos == -1) return false;
FENZHONG = 0; bool dian = false; double base = 0.1;
for(int i = 1; i < mhpos; i++){
if(str[i] == '.'){
if(dian) return false;
dian = true;
continue;
}
if(dian){
FENZHONG += base * (str[i] - '0');
base /= 10;
continue;
}
if(!isdigit(str[i])) return false;
FENZHONG = FENZHONG * 10 + str[i] - '0';
}
MIAOSHU = 0; dian = false; base = 0.1;
for(int i = mhpos + 1; i < str.length() - 1; i++){
if(str[i] == '.'){
if(dian) return false;
dian = true;
continue;
}
if(dian){
MIAOSHU += base * (str[i] - '0');
base /= 10;
continue;
}
if(!isdigit(str[i])) return false;
MIAOSHU = MIAOSHU * 10 + str[i] - '0';
}
return true;
}
signed main(){
// freopen("lrc.in", "r", stdin);
// freopen("lrc.out", "w", stdout);
cin >> n; getline(cin, s);
for(int i = 1; i <= n; i++){
getline(cin, s);
// cout << s << endl;
int mxl = -1;
for(int j = 0; j < s.length(); j++){
if(s[j] == '['){
for(int k = j + 1; k < s.length(); k++){
if(s[k] == ':'){
for(int l = k + 1; l < s.length(); l++){
if(s[l] == ']'){
// j = l;
string str = "";
for(int m = j; m <= l; m++) str += s[m];
tag[i].push_back(str);
mxl = max(mxl, l);
j = l;
goto nxt;
}
}
}
}
}
nxt: continue;
}
string gc;
for(int j = mxl + 1; j < s.length(); j++){
gc += s[j];
}
geci[i] = gc;
}
// for(int i = 1; i <= n; i++){
// for(auto p : tag[i]){
// cout << p << endl;
// }
// cout << geci[i] << endl;
// cout << endl;
// }
vector<pair<double, string> > ans;
for(int i = 1; i <= n; i++){
for(auto p : tag[i]){
if(istimetag(p)){
// cout << p << " " << FENZHONG << " " << MIAOSHU << endl;
ans.push_back({FENZHONG*60+MIAOSHU, geci[i]});
}
}
}
sort(ans.begin(), ans.end());
for(auto p : ans) cout << p.second << '\n';
return 0;
}

浙公网安备 33010602011771号