2023杭电多校第八场 - 5 7 10
比赛地址:传送门
赛时过了 4 题,队友杀疯了,继续加油哈~
1005 思维题
1007 并查集板子
1008 求矩阵的秩的期望
1010 数学思维题
1005 0 vs 1
题意
有两个选手 0 和 1 进行一场游戏。给定一个长为 n 的 01 串,每位选手轮流从给定的01串的首尾选择移除一个字符。如果选手 0 移除字符 1 就输了,选手 1 移除字符 0 也输了。如果所有的字符均被移除了,则定为平局。选手 0 先进行操作。
每位选手均进行最优操作,问你最终的结果?
思路
假设当前是选手 f 进行操作
-
如果当前字符串首尾不等,那么选手 f 没有选择,只能选相应的数字进行操作
-
如果当前字符串首尾相等
-- 首先判断当前选手 f 移除首尾字符是否必输
-- 在不必输的情况下,考虑次首尾字符串是否存在相同的字符构成必胜取法,即11...1 / 0...00这种情况的字符串
-- 如果没有必胜取法,则看次次位首尾字符是否有与首尾相同的字符,如有则选,即如101...01的情况选移除首位字符。此操作的目的是为了限制对手的操作,使得局势优先权回到选手 f 身上来
-- 如果首尾次次位均没有相同字符串,此时选手 f 操作哪边结果都一样,随意选即可
此操作流程需要特判 n = 1 的情况
详见代码
代码
//>>>Qiansui
#include<bits/stdc++.h>
// #define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
int n, ans;
string ss, c = "01";
void solve(){
cin >> n >> ss;
if(n == 1){
cout << (ss == "0" ? -1 : 1) << '\n';
return ;
}
ans = -1;
int l = 0, r = ss.size() - 1, f = 0;
while(l <= r){
if(ss[l] == ss[r]){ //左右相等
if(ss[l] != c[f]){ //当前选手操作必输
ans = 1 - f; break;
}
if(r == l + 1) ++ l;
else{
if(ss[l + 1] == ss[l]) ++ l;
else if(ss[r - 1] == ss[r]) -- r;
else{ //左右目前没有连续相同的,那就次位是否有相同的
if(ss[l] == ss[l + 2]){
++ l;
}else -- r;
}
}
}else{ //左右不等
if(ss[l] == c[f]) ++ l;
else -- r;
}
f = 1 - f;
}
cout << ans << '\n';
return ;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
cin >> _;
while(_ --){
solve();
}
return 0;
}
1007 Solubility
题意
不翻译啦~ 题面蛮长但是题目简单
思路
并查集判断给定点是否在一个连通块内
代码
struct dsu{
int num;
vector<int> fa;
dsu(int x = maxm):num(x),fa(x + 1){
for(int i = 0; i <= x; ++ i) fa[i] = i;
}
int findfa(int x){ return fa[x] == x ? x : fa[x] = findfa(fa[x]); }
void merge(int u,int v){
fa[findfa(u)] = findfa(v); return ;
}
bool same(int u, int v){ return findfa(u) == findfa(v); }
};
void solve(){
int n, m;
cin >> n >> m;
dsu ds(n);
int u, v;
for(int i = 0; i < m; ++ i){
cin >> u >> v;
ds.merge(u, v);
}
int k;
cin >> k;
bool f = true;
for(int i = 0; i < k; ++ i){
cin >> u;
if(f && i){
if(!ds.same(u, v)) f = false;
}
v = u;
}
if(f) cout << "YES\n";
else cout << "NO\n";
return ;
}
1008 Expectation of Rank - 理解中
题意
思路
还在理解中
代码
队友赛时代码
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
int T, n, F[5005][5005], p, S[5005], ans, inv;
const int mod = 1e9 + 7;
int qpow(int a, int x)
{ // 模意义下取幂
a %= mod;
int res = 1;
while (x > 0)
{
if (x & 1)
res = (res * a) % mod;
a = (a * a) % mod;
x >>= 1;
}
return res;
}
void solve()
{
cin >> n >> p;
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= n; j++)
{
F[i][j] = 0;
}
}
S[0] = 1;
for (int i = 1; i <= n; i++)
{
S[i] = 1ll * S[i - 1] * p % mod;
}
F[0][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int k = 0; k < i; k++)
{
F[i][k] = (F[i][k] + 1ll * F[i - 1][k] * S[k]) % mod;
F[i][k + 1] = (F[i][k + 1] + 1ll * F[i - 1][k] * (S[n] - S[k] + mod) % mod) % mod;
}
}
for (int i = 0; i <= n; i++)
ans = (ans + 1ll * F[n][i] * i) % mod;
inv = qpow(S[n], n);
inv = qpow(inv, mod - 2);
ans = 1ll * inv * ans % mod;
cout << ans << endl;
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
while (t--)
{
ans = 0;
inv = 0;
solve();
}
return 0;
}
1010 Rikka with Square Numbers
题意
给定数 \(a\) 和数 \(b\) $(a \ne b) $,你的任务是利用最少的操作次数,使得数字 a 变成数字 b。
每次操作你可以给当前数加上或者减去任意一个完全平方数。
问你最少的操作次数?
思路
我们考虑数 a 和数 b 的差值 cha
-
当 cha 是完全平方数的时候,只需要 1 步
-
当 cha 不是完全平方数的时候,但当差值为奇数的时候,只需要两步
因为 $(k + 1)^2 - k^2 = 2k + 1,k \ge 1 $,所以剩下的任意的奇数均可以被表示 -
当 cha 不是完全平方数的时候,但当差值为偶数的时候
因为 $(k + 2)^2 - k^2 = 4k + 4, k \ge 1 $,则剩下的 4 的倍数均可以被表示,仅需要 2 步即可
其余不可以被 4 整除的偶数,如果其差值可以被两个完全平方数表示时,答案为 2
否则可以通过奇数 +-1 的方式实现,可以得知这是最少的操作次数,答案为 3
代码
void solve(){
ll a, b;
cin >> a >> b;
ll cha = abs(a - b), ans, squ = sqrt(cha);
if(squ * squ == cha) ans = 1;
else if(cha % 2 || cha % 4 == 0) ans = 2;
else{
ans = 3;
for(int i = 1; i * i <= cha; ++ i){
ll t = cha - i * i;
squ = sqrt(t);
if(squ * squ == t){
-- ans; break;
}
}
}
cout << ans << '\n';
return ;
}