本次比赛是我打a以来最接近AK的一次,打的也非常顺,看了下大部分是构造以及数学题,我还是喜欢这两类。
比赛链接牛客2025秋季算法编程训练联赛5-基础组
A-模板 题意 给出有且仅由大写字母构成,长度为 $n$ 的字符串s1 以及长度为 $m$ 的字符串s2,求最小操作可以将其中一个字符串转化为另一个,操作有:
将其中任意一个字母替换为另一个
把最后一个字母删除
在尾部添加一个字母
其中,$1 \leq n,m \leq 10^5$
思路 既然可以修改任意一个,或者修改(删除添加)末尾,那么直接统计在 $i:=0 \sim \min(n,m)$ 中s1[i]!=s2[i] 的个数(超过min(n,m)的直接删了,里面的修改),最后加上n和m的差输出即可
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <bits/stdc++.h> using namespace std;int main () { ios::sync_with_stdio (false ); cin.tie (0 ); int n,m; cin >> n >> m; string s1,s2; cin >> s1 >> s2; int cnt=0 ; int len=min (n, m); for (int i=0 ; i<len; i++)if (s1[i]!=s2[i])cnt++; int ext=abs (n-m); cout << cnt+ext << endl; return 0 ; }
B-I题是个签到题 题意 给出$9 \le n \le 13 \ ,\ 100 \le m \le 1000$ 分别代表比赛的总题数和比赛的人数,定义签到题:
通过人数大于等于全场人数的 $80%$
或者通过人数是所有题目前三多的题(也就是最多有两个题目通过人数严格比它多)
求I题是不是签到题
思路 直接模拟即可
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <bits/stdc++.h> using namespace std;int main () { ios::sync_with_stdio (false ); cin.tie (0 ); int n,m; cin >> n >> m; vector<int > a (n) ; for (auto &x:a)cin >> x; int ti=a[8 ]; bool f1=((double )ti>=(double )m*0.8 ); int cnt=0 ; for (int i=0 ; i<n; i++)if (a[i]>ti)cnt++; bool f2=(cnt<=2 ); if (f1 || f2)cout << "Yes\n" ; else cout << "No\n" ; return 0 ; }
C-牛牛战队的秀场 题意 给出一个整数半径为 $1 \le r \le 10^6$ 的圆,以及里面的内接 $3 \le n \le 1000$ 边形,两个人分别在n边形的第 $i,j$ 号顶点,求两人经过多边形的边的最短距离。
思路 由于两点的位置是在一个环上,那么最短经过的边数应该是 $\min(|i-j|,n-|i-j|)$ 也就是正向和反向走的最小值,这个值乘上每条边的长度就是答案。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <bits/stdc++.h> using namespace std;const double PI=acos (-1.0 );int main () { ios::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); double n,r; cin >> n >> r; int i, j; cin >> i >> j; double l0=2.0 *r*sin (PI/n); int st=abs (i-j); int stp=(int )n-st; int minn=min (st,stp); double ans=(double )minn*l0; printf ("%.10lf" ,ans); return 0 ; }
D-Enjoy the game
看到博弈,被南京站的博弈吓怕了,蒟蒻以为很难,所以先跳过,写完F回来猜猜法猜出了答案,但是没敢交,后来严格证明发现是对的,可惜😭
题意 Bob和Alice进行一场比赛,初始有 $n$ 张牌,Bob和Alice轮流取牌,Bob先取,先取的牌数范围是 $1 \sim n-1$ ,接下来的每一步双方至少要取一张牌,且不能超过上一步对方所取得牌数,如果最后一张牌被Bob取走,Bob获胜,否则Alice获胜。双方都很聪明,输出谁会获胜。
思路 我们先打表一下:
$n$
Who will win
2
Alice
3
Bob
4
Alice
5
Bob
6
Bob
7
Bob
8
Alice
依此来看,如果n是奇数,Bob和Alice依次拿一张牌,Bob必胜,下面讨论n是偶数的情况:
如果Alice能赢,那么回合数一定是偶数;不想让Alice赢的话,每次拿出的牌数必须满足 $(n-x)/x$ 是偶数,并且此时的 $x<n/2$ 。
那么考虑 $n=2^k$ 时, 每次拿去 $x=n/2-1$ 后必定会剩下 $2^p+1$ 张牌,如果此时Alice拿去1张,又会递归到 $n=2^k$ 的情况。
注意到 $n={2,4,8}$ 时推断出ALice必胜,那么不难证明,$n=2^k$ 时Alice必胜。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <bits/stdc++.h> using namespace std;#define ll long long int main () { ios::sync_with_stdio (false ); cin.tie (0 ); ll n; cin >> n; if (n&1 ) { cout << "Bob\n" ; return 0 ; } else { if ((n&(n-1LL ))==0LL )cout << "Alice\n" ; else cout << "Bob\n" ; } return 0 ; }
E-Hash 题意 对于这样的hash函数
1 2 3 4 5 6 7 8 9 10 11 const int LEN = 6 ;int mod;int Hash (char str[]) { int res = 0 ; for (int i = 0 ; i < LEN; i++) { res = (res * 26 + str[i] - 'a' ) % mod; } return res; }
给出一个长度位6且仅有小写字母构成的字符串s,和模数mod,找到字典序最小且大于s的一个长度为6的字符串s’,使得其俩的hash值相等。
思路 这题一看就是26进制的模数,利用模数的周期性就可以AC。具体来看如何利用。
我们这里考虑原字符串s的26进制数 $h0$(先不 $\mathbf{mod}$ ),我们知道
那么我们只需要将 $h0$ 加上一个模数,就可以将这个hash转到下一个周期,然后从这个新的hash中用26进制转化为字符串s’。
蒟蒻这里先wa了三发,给大家看看我的神奇构造
先修改最后一位S[5],如果S[5]+mod还在25这个范围内,说明刚好下一个周期,直接输出修改后的即可
如果不能修改,那么构造最小修改:
需要构造的 $h’-h_0=0$
遍历 $i:=4~0$ 修改S[i],直接构造S[i]++,并同时修改S[5]补齐模数
此时S[5]应该等于$S[5]-w(5-i)$,权 $w(i)=26^{i} \mod m$
这个构造使得
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 const ll maxn=308915775 ; void sol (string s,int mod) { ll h0=0 ; for (int i=0 ; i<6 ; i++)h0=(h0*26 +s[i]-'a' ); ll h=h0+mod; if (h>maxn) { cout << "-1\n" ; return ; } string ans (6 ,'a' ) ; for (int i=5 ; i>=0 ; i--) { ans[i]='a' +(h%26 ); h/=26 ; } cout << ans << endl; return ; } int main () { ios::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); int mod; string s; while (cin >> s >> mod) sol (s,mod); return 0 ; }
F-牛牛战队的比赛地 题意 二维平面上有 $n$ 和点 $(x_i,y_i)$ ,在x轴上找到一个点,使得这些点到这个点的最大距离最小。
思路 显然的,找到最大的最小值,要么二分要么三分。
如果二分,我的想法是二分x轴上的点以及以这个点作为圆心画出的圆,最大包裹所有点,但是这样写就会很复杂。
考虑三分,显然存在某个点 $(x_0,0)$ 是该函数的极小值点,写出函数为:
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 const double eps=1e-9 ;int n;vector<pdd> g; double f (double x) { double res=-1e9 ; for (auto [xi,yi]:g) res=max (res,(x-xi)*(x-xi)+yi*yi); return res; } int main () { ios::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); cin >> n; g.resize (n); for (auto &[x,y]:g)cin >> x >> y; double l=-1e4 , r=1e4 ; for (int i=0 ; i<100 ; i++) { double m1=l+(r-l)/3.0 ; double m2=r-(r-l)/3.0 ; if (f (m1)>f (m2))l=m1; else r=m2; } double ans=sqrt (f ((l+r)/2.0 )); printf ("%.10lf" ,ans); return 0 ; }