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 ;
}
posted on 2023-08-10 18:59  Qiansui  阅读(4)  评论(0编辑  收藏  举报