2023 + 2024 百度之星部分题摘记

百度之星合集链接
2023百度之星
2024百度之星

2023百度之星

初赛一

1 公园

三遍 dij 求最短

//>>>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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 4e4 + 5, mod = 998244353;
const ll inf = 1e10;
vector<int> e[maxm];
int te, fe, s, t, f, n, m;
vector<vector<ll>> dis;

void dij(int u, int c){
	dis[c][u] = 0;
	vector<bool> vis(n + 1, false);
	priority_queue<pii, vector<pii>, greater<pii>> q;
	for(auto v : e[u]){
		q.push({1, v});
	}
	while(!q.empty()){
		pii t = q.top(); q.pop();
		// debug2(t.first, t.second);
		if(vis[t.second]) continue;
		vis[t.second] = true;
		dis[c][t.second] = t.first;
		for(auto v : e[t.second]){
			if(!vis[v] && dis[c][v] > dis[c][t.second] + 1){
				q.push({dis[c][t.second] + 1, v});
			}
		}
	}
	return ;
}

void solve(){
	cin >> te >> fe >> s;
	cin >> t >> f >> n >> m;
	dis = vector<vector<ll>> (3, vector<ll> (n + 1, inf));
	for(int i = 0; i < m; ++ i){
		int x, y;
		cin >> x >> y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dij(t, 0);
	dij(f, 1);
	dij(n, 2);
	ll ans = inf;
	for(int i = 1; i <= n; ++ i){
		ans = min(ans, dis[0][i] * te + dis[1][i] * fe + dis[2][i] * (te + fe - s));
	}
	if(ans == inf) cout << "-1\n";
	else cout << ans << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

5 糖果促销

先买 1 糖果,接下来每次买 p - 1 个糖果即可再换出一个糖果,如此循环,不足 p - 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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;

void solve(){
	ll p, k;
	cin >> p >> k;
	if(k == 0){
		cout << "0\n";
		return ;
	}
	ll n = k / p, ans = 1;
	ll yu = k - n * p;
	if(yu) -- yu;
	ans = n * (p - 1) + yu + 1;
	cout << ans << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

8 除法游戏 - 还在理解中

nim 游戏改版,本题的关键在于怎么快速求出每堆石子的 sg 值
假设某堆石子数为 t

  • \(t = 2 ^ k\) 为 2 的幂次时,其仅能被划分为偶数堆,每堆石子数相等,易知这些石子堆异或的结果一定是 0,所以此时 \(sg(2^k) = 1\)
  • 剩下的情况,如果划分为偶数堆时,sg 值异或和一定为0;那么最终影响 sg 值的仅有划分为奇数堆石子,又因为每次划分后的每堆石子均相等,那么划分为这一划分的 sg 值即为 \(sg(\frac{t}{p})\),p 为奇数
    那其实就相当于,每次操作可以都可以从一堆石子中取出一些奇因子

那么,最终 \(sg(t) = \lfloor 2 | t \rfloor + cnt_{奇因子个数}\)

那么对于每一堆石子求出其 sg 值,再利用 sg 定理即可

下为代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define lll __int128
#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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxn = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;

lll qmksm(ll a,ll b,ll m){
	lll s=1,z=a%m;
	while(b>0){
		if(b&1==1){
			s*=z;
			s%=m;
		}
		z*=z;
		z%=m;
		b>>=1;
	}
	return s;
}

bool millerrabin(ll n){
	if(n<3) return n==2;
	if(n%2==0) return 0;
	ll i,j,d=n-1,r=0,tss[8]={-1,2,325,9375,28178,450775,9780504,1795265022};
	while(d%2==0) d/=2,r++;
	for(i=1;i<=7;i++){
		lll zc=qmksm(tss[i],d,n);
		if(zc<=1 or zc==n-1) continue;
		for(j=0;j<=r-1;j++){
			zc=(zc%n*zc%n)%n;
			if(zc==n-1 and j!=r-1){
				zc=1;
				break;
			}
			if(zc==1) return 0;
		}
		if(zc!=1) return 0;
	}
	return 1;
}

int N = 1e4 + 5, cnt = 0;
vector<bool> isprime(N, true);//判断素数
vector<long long> prime;//存储素数
void pre(){
	long long t;
	isprime[1] = false;
	for(long long i = 2; i < N; ++ i){
		if(isprime[i]){
			prime.push_back(i);
			++ cnt;
		}
		for(int j = 0; j < cnt; ++ j){
			t = i * prime[j];
			if(t > N) break;
			isprime[t] = false;
			if(i % prime[j] == 0) break;
		}
	}
	return ;
}

void solve(){
	pre();
	int n;
	cin >> n;
	int sum = 0;
	for(int i = 0; i < n; ++ i){
		ll cur, c = 0;
		cin >> cur;
		if(cur % 2 == 0) c = 1;
		while(cur % 2 == 0) cur /= 2;
		for(int j = 0; j < cnt; ++ j){
			while(cur % prime[j] == 0){
				++ c;
				cur /= prime[j];
			}
		}
		if(cur != 1){
			++ c;
			if(!millerrabin(cur)) ++ c;
		}
		sum ^= c;
	}
	puts(sum ? "Xiaodu" : "Duduxiong");
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

初赛二

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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 1e5 + 5, maxn = 1e6 + 5, inf = 0x3f3f3f3f, mod = 998244353;
ll n, x[3][maxm];

void solve(){
	cin>> n;
	for(int i = 1; i <= n; ++ i){
		cin >> x[0][i] >> x[1][i] >> x[2][i];
	}
	sort(x[0] + 1, x[0] + n + 1);
	sort(x[1] + 1, x[1] + n + 1);
	sort(x[2] + 1, x[2] + n + 1);
	int t = n / 2;
	if(n % 2) ++ t;
	ll c[3] = {0, 0, 0};//同一点
	ll d[3] = {0, 0, 0};
	for(int i = 1; i <= n; ++ i){
		for(int j = 0; j <= 2; ++ j){
			c[j] += abs(x[j][t] - x[j][i]);
			int cha = i - t;
			d[j] += abs(x[j][t] + cha - x[j][i]);
		}
	}
	ll ans = 1e18;
	ans = min(ans, d[0] + c[1] + c[2]);
	ans = min(ans, d[1] + c[0] + c[2]);
	ans = min(ans, d[2] + c[1] + c[0]);
	cout << ans << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

3 夏日漫步

//>>>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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 2e5 + 5, maxn = 1e6 + 5, inf = 0x3f3f3f3f, mod = 998244353;
int n, a[maxm];

void solve(){
	cin >> n;
	vector<int> dp(n + 1, inf), head(maxn, -1);
	dp[0] = dp[1] = 0;
	for(int i = 1; i <= n; ++ i){
		cin >> a[i];
		dp[i] = min(dp[i - 1] + 1, dp[i]);
		if(head[a[i]] != -1) dp[i] = min(dp[i], dp[head[a[i]]] + 1);
		int t = i;
		while(t > 1 && dp[t - 1] > dp[t] + 1){
			dp[t - 1] = dp[t] + 1;
			-- t;
		}
		head[a[i]] = i;
	}
	cout << dp[n];
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

4 怪兽

纯纯暴力过

//>>>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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
const ll INF = 0x3f3f3f3f3f3f3f3f;

void solve(){
	ll p, q, n1, n2, n3;
	cin >> p >> q >> n1 >> n2 >> n3;
	ll ma = -1, mn = p + 1;
	for(ll x1 = 0; x1 * n1 <= q; ++ x1){
		for(ll x2 = 0; x2 * n2 + x1 * n1 <= q; ++ x2){
			if(x2 * n2 + x1 * n1 + (p - x1 - x2) * n3 == q){
				ma = max(ma, p - x1 - x2);
				mn = min(mn, p - x1 - x2);
			}
		}
	}
	if(ma != -1) cout << mn << ' ' << ma << '\n';
	else cout << "-1\n";
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

6 跑步

//>>>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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 1e5 + 5, maxn = 1e6 + 5, inf = 0x3f3f3f3f, mod = 998244353;
int n;
struct node{
	int sz = 0, pos, mv = inf;
}p[maxm];

void solve(){
	map<int, int> q;
	int cnt = -1;
	cin >> n;
	int pos, v, t;
	for(int i = 0; i < n; ++ i){
		cin >> pos >> v;
		if(q.count(pos)) t = q[pos];
		else{
			t = ++ cnt;
			q[pos] = t;
		}
		++ p[t].sz;
		p[t].pos = pos;
		p[t].mv = min(p[t].mv, v);
	}
	sort(p, p + cnt + 1, [](node x, node y){
		return x.pos < y.pos || x.pos == y.pos && x.mv < y.mv;
	});
	vector<pii> pre;//v, sz
	int ans = 0;
	for(int i = 0; i <= cnt; ++ i){
		ans = max(ans, p[i].sz);
		if(p[i].mv == 1 && pre.empty()) continue;
		if(pre.empty()){
			pre.push_back({p[i].mv, p[i].sz});
		}else if(p[i].mv >= pre.back().first){
			pre.push_back({p[i].mv, p[i].sz});
		}else{
			auto it = upper_bound(pre.begin(), pre.end(), make_pair(p[i].mv, inf));
			int id = it - pre.begin();
			for(int j = id; j < pre.size(); ++ j){
				p[i].sz += pre[j].second;
			}
			pre.erase(it, pre.end());
			ans = max(ans, p[i].sz);
			if(p[i].mv > 1) pre.push_back({p[i].mv, p[i].sz});
		}
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

初赛三

1 石碑文

状态:
统计字符串长度为 i 的已经匹配上"shsshsshs"中 j 个字符的方案数
考虑字符串末尾情况,仅有 4 种情况:"","..s","..sh","..shs","..*"

转移:
五种情况相互进行转移
"" -> "s"
"" -> "*"

"..s" -> "..sh"
"..s" -> "..s"
"..s" -> "..*"

"..sh" -> "..shs"
"..sh" -> "..*"

"..shs" -> "..shs" (前缀满足有至少3个"shs")
"..shs" -> "..s"
"..shs" -> "..
"

"..*" -> "..s"

据此,思路完全打开,可以写题了

//>>>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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 1e6 + 5, inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 1e9 + 7;
int n;
ll dp[maxm][10]; // dp[i][j] 表示到第i个字符已经匹配上"shsshsshs"中j个字符的方案数

void solve(){
	cin >> n;
	dp[0][0] = 1;
	for(int i = 0; i < n; ++ i){
		for(int j = 0; j < 10; ++ j){
			if(j == 9){// "shsshsshs"已经完全匹配
				dp[i + 1][j] = (dp[i + 1][j] + dp[i][j] * 26) % mod;
			}else if(j % 3 == 1){
				dp[i + 1][j] = (dp[i + 1][j] + dp[i][j]) % mod;// "..s" -> "..ss"
				dp[i + 1][j + 1] = (dp[i + 1][j + 1] + dp[i][j]) % mod; // "..s" -> "..sh"
				dp[i + 1][j - 1] = (dp[i + 1][j - 1] + dp[i][j] * 24) % mod; //"..s" -> "..s*"(*代表除"sh"以外的任意字符)
			}else{// "...sh" / "...shs"
				dp[i + 1][j + 1] = (dp[i + 1][j + 1] + dp[i][j]) % mod; // "..." + "s"
				dp[i + 1][j / 3 * 3] = (dp[i + 1][j / 3 * 3] + dp[i][j] * 25) % mod; // 清空后缀
			}
		}
	}
	cout << dp[n][9] << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

5 新材料

遍历统计即可

//>>>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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 1e6 + 5, inf = 0x3f3f3f3f, mod = 998244353;
const ll INF = 0x3f3f3f3f3f3f3f3f;

void solve(){
	int n, k;
	cin >> n >> k;
	map<int, int> q;
	vector<bool> f(maxm + 1, false);
	for(int i = 0; i < n; ++ i){
		int t;
		cin >> t;
		if(q.count(t)){
			if(i - q[t] <= k) f[t] = true;
		}
		q[t] = i;
	}
	int ans = 0;
	for(int i = 0; i <= maxm; ++ i){
		if(f[i]) ans ^= i;
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

6 与蝴蝶一起消散吧

DP~
后面的转移再理解理解!!!
知道赛时为啥没出嘛?因为爆int了!!!输入的a,m相乘爆int了!!!

//>>>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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 998244353;

void solve(){
	int n, k;
	cin >> n >> k;
	ll ans0 = 0, ans1 = 0;
	for(int i = 1; i <= n; ++ i){
		ll a, m;
		cin >> a >> m;
		if(a > k){//有技能就放
			ans0 = ans1 = min(ans0 + k, ans1) + (a - k) * m;// 最终状态一样,有无技能均可视为
		}else{// 一刀秒时
			ll t0 = min(ans0 + (m + 1) / 2 * a, ans1 + m / 2 * a);// 最终无技能
			ll t1 = min(ans0 + (m + 2) / 2 * a, ans1 + (m + 1) / 2 * a);// 最终有技能
			ans0 = t0; ans1 = t1;
		}
	}
	cout << min(ans0, ans1) << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

赛时代码改ll

//>>>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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
const ll INF = 0x3f3f3f3f3f3f3f3f;

void solve(){
	int n, k;
	cin >> n >> k;
	vector dp(n + 1, vector<ll>(2, INF));
	dp[0][0] = dp[0][1] = 0;
	for(int i = 1; i <= n; ++ i){
		ll a, m;
		cin >> a >> m;
		if(a <= k){
			if(m % 2){
				dp[i][0] = min(dp[i][0], dp[i - 1][1] + (m - 1) / 2 * a);
				dp[i][1] = min(dp[i][1], dp[i - 1][0] + a + (m - 1) / 2 * a);
				dp[i][1] = min(dp[i][1], dp[i - 1][1] + a + (m - 1) / 2 * a);
			}else{
				dp[i][0] = min(dp[i][0], dp[i - 1][0] + m / 2 * a);
				dp[i][0] = min(dp[i][0], dp[i - 1][1] + m / 2 * a);
				dp[i][1] = min(dp[i][1], dp[i - 1][1] + m / 2 * a);
				dp[i][1] = min(dp[i][1], dp[i - 1][0] + a * 2 + (m - 2) / 2 * a);
			}
		}else{
			dp[i][1] = min(dp[i][1], dp[i - 1][0] + a + (m - 1) * (a - k));
			dp[i][1] = min(dp[i][1], dp[i - 1][1] + m * (a - k));
			dp[i][0] = min(dp[i][0], dp[i - 1][1] + m * (a - k));
		}
	}
	cout << min(dp[n][0], dp[n][1]) << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

决赛

1 找矩阵

赛时代码

//Author: Qiansui
//Time: 2023-12-31 08:18
#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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int N = 3e3 + 5, inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 998244353;
int n, m, sx, sy;
string ss[N];

void solve(){
	cin >> n >> m;
	bool fs = true;
	for(int i = 0; i < n; ++ i){
		cin >> ss[i];
		for(int j = 0; j < m && fs; ++ j){
			if(ss[i][j] == 'S'){// 找到S的位置
				fs = false;
				sx = i; sy = j;
				break;
			}
		}
	}
	// debug2(sx, sy);
	vector<int> rax(m, sx), rmn(m, sx), cax(n, sy), cmn(n, sy);
	// 行上下最大
	for(int i = 0; i < m; ++ i){// 对S行,i列
		if(ss[sx][i] != '#'){
			for(int j = sx - 1; j >= 0; -- j){// 向上
				if(ss[j][i] == '.') rmn[i] = j;
				else break;
			}
			for(int j = sx + 1; j < n; ++ j){// 向下
				if(ss[j][i] == '.') rax[i] = j;
				else break;
			}
		}
	}
	// for(int i = 0; i < m; ++ i){
	//     cout << i << " : ";
	//     debug2(rmn[i], rax[i]);
	// }
	// 列左右最大
	for(int i = 0; i < n; ++ i){// i行
		if(ss[i][sy] != '#'){
			for(int j = sy - 1; j >= 0; -- j){
				if(ss[i][j] == '.') cmn[i] = j;
				else break;
			}
			for(int j = sy + 1; j < m; ++ j){
				if(ss[i][j] == '.') cax[i] = j;
				else break;
			}
		}
	}
	// for(int i = 0; i < n; ++ i){
	//     cout << i << " : ";
	//     debug2(cmn[i], cax[i]);
	// }

	for(int i = 0; i < n; ++ i){// 行可能
		if(i == sx) continue;
		bool l = false, r = false, mid = (rmn[sy] <= i && i <= rax[sy]);
		for(int j = max(cmn[sx], cmn[i]); j < sy; ++ j){// 判断j列是否能到S
			if(rmn[j] <= i && i <= rax[j]){
				l = true; break;
			}
		}
		for(int j = sy + 1; j <= min(cax[sx], cax[i]); ++ j){// 判断j列是否能到S
			if(rmn[j] <= i && i <= rax[j]){
				r = true; break;
			}
		}
		if((mid && (l || r)) || l && r){
			// debug(i);
			// cout << "hang\n";
			cout << "Yes\n";
			return ;
		}
	}
	for(int j = 0; j < m; ++ j){// 列可能
		if(j == sy) continue;
		bool u = false, d = false, mid = (cmn[sx] <= j && j <= cax[sx]);
		for(int i = max(rmn[sy], rmn[j]); i < sx; ++ i){// 行i是否可达列S
			if(cmn[i] <= j && j <= cax[i]){
				u = true; break;
			}
		}
		for(int i = sx + 1; i <= min(rax[sy], rax[j]); ++ i){// 行i是否可达列S
			if(cmn[i] <= j && j <= cax[i]){
				d = true; break;
			}
		}
		if(u && d || (u || d) && mid){
			// cout << "lie\n";
			cout << "Yes\n";
			return ;
		}
	}

	cout << "No\n";
	return ;
}

signed main(){
	// freopen("in.txt", "r", stdin);
	// freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

2 错峰旅行

赛时代码

//Author: Qiansui
//Time: 2023-12-31 10:20
#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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int N = 1e6 + 5, inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 1e9 + 7;
int n, m, s, t;

ll qpow(ll a, ll x){
	a %= mod;
	ll res = 1;
	while(x){
		if(x & 1) res = res * a % mod;
		x >>= 1;
		a = a * a % mod;
	}
	return res;
}

void solve(){
	cin >> n >> m >> s >> t;
	vector<pii> d;
	for(int i = 0; i < m; ++ i){
		int x, l, r;
		cin >> x >> l >> r;
		d.push_back({l, -1});
		d.push_back({r + 1, 1});
	}
	d.push_back({t + 1, 0});
	sort(d.begin(), d.end());
	ll ans = 1, now = s - 1, num = n, sz = d.size();
	for(int i = 0; i < sz;){
		int day = d[i].first;
		int len = day - 1 - now;
		ans = ans * qpow(num, len) % mod;
		// debug2(day, ans);
		// debug2(num, len);
		// debug(now);
		do{
			num += d[i].second;
			++ i;
		}while(i < sz && d[i - 1].first == d[i].first);
		now = day - 1;
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	// freopen("in.txt", "r", stdin);
	// freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

4 传信游戏

赛时代码

//Author: Qiansui
//Time: 2023-12-31 08:18
#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<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int N = 1e3 + 5, inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 998244353;
int n, p[N], ans = 0, in[N], vis[N];
bool ok[N];
vector<int> s[N];

void dfs(int u){
	bool f = true;
	ok[u] = true;
	for(int i = u; i; i = p[i]){
		vis[i] = u;
		s[u].push_back(i);
		if(vis[p[i]] != 0){
			if(vis[p[i]] == u){
				f = false;
				ok[u] = false;
			}else if(!ok[vis[p[i]]]){
				f = false;
				ok[u] = false;
			}
			break;
		}
	}
	return ;
}

void solve(){
	cin >> n;
	for(int i = 1; i <= n; ++ i){
		cin >> p[i];
		++ in[p[i]];
	}
	for(int i = 1; i <= n; ++ i){
		if(in[i] == 0){
			// debug(i);
			dfs(i);
		}
	}
	ans = 0;
	for(int i = 1; i <= n; ++ i){
		if(ok[i]){
			// cout << "i: " << i << '\n';
			for(auto x : s[i]){
				// cout << x << ' ';
				ans ^= x;
			}
			// cout << '\n';
		}
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	// freopen("in.txt", "r", stdin);
	// freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

2024 百度之星

初赛一

1 补给

注意数据范围,贪心枚举哪一个堡垒使用优惠即可

#include<bits/stdc++.h>

using namespace std;

void solve(){
	int n, b;
	cin >> n >> b;
	vector<int> p(n), s(n);
	multiset<int> tot;
	for(int i = 0; i < n; ++ i){
		cin >> p[i] >> s[i];
		tot.insert(p[i] + s[i]);
	}
	int ans = 0;
	for(int i = 0; i <= n; ++ i){
		if(i){
			tot.erase(tot.find(p[i - 1] + s[i - 1]));
			tot.insert(p[i - 1] / 2 + s[i - 1]);
		}
		if(i > 1){
			tot.erase(tot.find(p[i - 2] / 2 + s[i - 2]));
			tot.insert(p[i - 2] + s[i - 2]);
		}
		int t = b, cnt = 0;
		for(auto x : tot){
			if(t >= x){
				t -= x;
				++ cnt;
			}else break;
		}
		ans = max(ans, cnt);
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int _ = 1;
	// cin >> _;
	while(_--){
		solve();
	}
	return 0;
}

2 跑步

数论题,用到了思维 + 线性筛 + 线性求逆元

首先,得明白什么时候同时到达终点?显然是跑步的总时间是 $ lcm(1, 2, \cdots, n) $

其次,随便两个人之间到底会打多少次招呼?假设 1 ~ n 的最小公倍数为 \(m\),考虑第 \(i\) 名同学和第 \(j\) 名同学\((i < j)\),那么他俩之间打招呼的次数就是 $ \frac{m}{i} - \frac{m}{j} $ (为什么多想想就通了)

接下来考虑每位同学对于答案的贡献。对于第 \(i\) 名同学,与第 1 ~ i-1 同学打招呼时,其对答案产生负贡献 \(i - 1\) 次;与 i + 1 ~ n 名同学打招呼时,其对答案产生正贡献 \(n - i\) 次。那么,每一位同学对于答案的贡献就是 \((n - i * 2 + 1)\) 次 $ \frac{m}{i} $。

所以最终答案就是将所有的贡献在模意义下相加即可。

还存在几个问题。

  • lcm怎么算?考虑质数,我们只需要考虑 \([1, n]\) 范围内的所有质数,对于每一个质数算出其最高幂次的不超过 \(n\) 的值,再将所有乘在一起即为 lcm,即 $ lcm = \prod_{p <= n 且 p 为质数}{p ^ { \lfloor {log_{p}^{n}} \rfloor } } $
  • 线性求 1 ~ n 的逆元见板子
//Author: Qiansui
//Time: 2024-06-07 16:44
#include<bits/stdc++.h>
#define ll long long
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'

using namespace std;
const ll mod = 998244353;

int N = 1e7 + 5;
vector<int> primes;
vector<bool> not_prime(N);

void pre(){
	not_prime[1] = true;
	for(int i = 2; i < N; ++ i){
		if(!not_prime[i])
			primes.push_back(i);
		for(int j = 0; j < primes.size() && primes[j] * i < N; ++ j){
			not_prime[primes[j] * i] = true;
			if(i % primes[j] == 0) break;
		}
	}
}

ll qpow(ll a, ll x){
	ll res = 1;
	a %= mod;
	while(x){
		if(x & 1) res = res * a % mod;
		x >>= 1;
		a = a * a % mod;
	}
	return res;
}

void solve(){
	pre();
	ll n, lcm = 1;
	cin >> n;
	for(auto x : primes){// 计算 1 ~ n 的 lcm
		if(x > n) break;
		lcm = lcm * qpow(x, log(n) / log(x)) % mod;
	}
	// 计算贡献
	int ans = 0;
	vector<int> inv(n + 1, 0);
	inv[1] = 1;
	for(int i = 1; i <= n; ++ i){
		if(i > 1) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
		ll tot = lcm * inv[i] % mod;
		ans = (ans + tot * (n - 2 * i + 1) % mod + mod) % mod;
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	// freopen("in.txt", "r", stdin);
	// freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

4 110串

DP
因为开的空间不大,所以采用 dp 和 t 的两个数组

总字符个数小于 3 时单独讨论;
总字符个数大于等于 3 时:
状态
\(dp[i][j][l]\) 表示修改了 \(i\) 个字符,且最后两个字符为 j 和 l 时的合法方案数
末尾两字符四种情况:00,01,10,11

转移
c 表示下一个字符

  • 当未出现 末尾呈现为 11 且下一字符为 0 时,可以不修改转移 t[i][l][c] = (t[i][l][c] + dp[i][j][l]) % mod;
  • 当未出现 末尾呈现为 11 且下一字符为 1 且还有修改次数时,可以修改转移 t[i + 1][l][1 - c] = (t[i + 1][l][1 - c] + dp[i][j][l]) % mod;
//Author: Qiansui
//Time: 2024-06-10 21:57
#include<bits/stdc++.h>
#define ll long long
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'

using namespace std;

void solve(){
	const ll mod = 998244353;
	ll n, k;
	string ss;
	cin >> n >> k >> ss;
	vector dp(k + 5, vector<vector<ll>>(2, vector<ll>(2, 0)));
	if(ss.size() < 3){
		cout << (1 << min((ll)ss.size(), k)) << '\n';
		return ;
	}
	// 00, 01, 10, 11
	dp[0][ss[0] - '0'][ss[1] - '0'] = 1;
	dp[1]['1' - ss[0]][ss[1] - '0'] = 1;
	dp[1][ss[0] - '0']['1' - ss[1]] = 1;
	dp[2]['1' - ss[0]]['1' - ss[1]] = 1;
	for(int id = 2; id < ss.size(); ++ id){
		int c = ss[id] - '0';
		vector t(k + 1, vector<vector<ll>>(2, vector<ll>(2, 0)));
		for(int i = 0; i <= k; ++ i)
			for(int j = 0; j < 2; ++ j)
				for(int l = 0; l < 2; ++ l)
					if(dp[i][j][l]){
						if(!(j == 1 && l == 1 && c == 0))
							t[i][l][c] = (t[i][l][c] + dp[i][j][l]) % mod;
						if(!(j == 1 && l == 1 && c == 1) && i < k)
							t[i + 1][l][1 - c] = (t[i + 1][l][1 - c] + dp[i][j][l]) % mod;
					}
		swap(dp, t);
	}
	ll ans = 0;
	for(int i = 0; i <= k; ++ i)
		for(int j = 0; j < 2; ++ j)
			for(int l = 0; l < 2; ++ l)
				ans = (ans + dp[i][j][l]) % mod;
	cout << ans << '\n';
	return ;
}

signed main(){
	// freopen("in.txt", "r", stdin);
	// freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

初赛二

1 还原汉诺塔

注意到,三步走的策略中,需要的操作次数为 $ 2^{n - 1} - 1 $ 、\(1\) 和 $ 2^{n - 1} - 1 $ 步

那么可以从大圆盘开始往小圆盘考虑,如果第 k 步的第 i 个字符是1,那么这个大圆盘在汉诺塔的递归过程中已经移到 c 盘上了,反之其还在 a 盘上;对于该圆盘上的剩下的圆盘也是同理,只不过汉诺塔对应过程中的柱序号需要发生变化

详见代码

void solve(){
	int n;
	string ss;
	cin >> n >> ss;
	string ans(n, 'A');
	char a = 'A', b = 'B', c = 'C';
	for(int i = 0; i < n; ++ i){
		if(ss[i] == '1'){
			ans[n - 1 - i] = c;
			swap(a, b);
		}else{
			ans[n - 1 - i] = a;
			swap(b, c);
		}
	}
	cout << ans << '\n';
	return ;
}

2 叠砖块

简单差分题

#include<bits/stdc++.h>

using namespace std;

void solve(){
	int n, k;
	cin >> n >> k;
	vector<int> cnt(n + 5);
	for(int i = 0; i < k; ++ i){
		int a, b;
		cin >> a >> b;
		++ cnt[a]; -- cnt[b + 1];
	}
	multiset<int> tot;
	int sum = 0;
	for(int i = 1; i <= n; ++ i){
		sum += cnt[i];
		tot.insert(sum);
	}
	int ans = 0, cs = 0;
	for(auto x : tot){
		++ cs;
		if(cs == n / 2 + 1){
			ans = x;
			break;
		}
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

4 括号

赛时的自己就像笨蛋一样,这都没想出来

首先,对于给定的括号序列,如果需要匹配成功,那么该序列的每一个前缀的左括号个数需要大于等于右括号个数,且整体的左括号个数和右括号个数相等

那么我们可以对于原序列,维护一个前缀左括号和右括号的差值,再维护一个该前缀的后缀最小值

对于一个位置来说,如果它可以修改,那么其应当满足对于它之前的序列差值均为正;它处于的这个位置的字符转换之后,它及后面的位置的差值均为正,且整体的左右括号数相等。

遍历所有位置,判断是否合法即可。

#include<bits/stdc++.h>
#define debug(x) cout << #x << " = " << x << '\n';
#define debug2(x, y) cout << #x << " = " << x << ' ' << #y << " = " << y << '\n';

using namespace std;

void solve(){
	string ss;
	cin >> ss;
	int n = ss.size();
	vector<int> pre(n + 5), las(n + 5);
	for(int i = 1; i <= n; ++ i){
		char ch = ss[i - 1];
		if(ch == '(') pre[i] = 1;
		else pre[i] = -1;
		pre[i] += pre[i - 1];
	}
	las[n + 1] = pre[n];
	for(int i = n; i >= 1; -- i){
		las[i] = min(las[i + 1], pre[i]);
	}
	int ans = 0;
	for(int i = 1; i <= n; ++ i){
		char ch = ss[i - 1];
		if(pre[i - 1] < 0) break;
		int t = ch == '(' ? -2 : 2;
		if(t + las[i] >= 0 && t + pre[n] == 0){
			++ ans;
		}
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

初赛三

1 数星星

void solve(){
	ll n;
	cin >> n;
	vector<pair<ll, ll>> a(n);
	for(int i = 0; i < n; ++ i){
		cin >> a[i].second;
	}
	for(int i = 0; i < n; ++ i){
		cin >> a[i].first;
	}
	ll l, r, c, mid, ans = -1;
	ll e, f;
	cin >> e >> f >> c;
	l = e; r = f;
	while(l <= r){// [e, f]
		mid = (l + r) >> 1;
		ll cnt = 0;
		for(auto [x, y] : a){// [max(e, x), mid]
			if(mid >= x){
				ll temp = (mid - x) / y + 1;
				temp -= max(0ll, max(e, x) - x - 1) / y + (max(e, x) - x - 1 >= 0);
				// if(max(e, x) - x == 0) ++ temp;
				cnt += temp;
				// cout << temp << " ";
			}
		}
		// cout << "\n";
		// cout << "mid: " << mid << " cnt: " << cnt << '\n';
		if(cnt >= c){
			r = mid - 1;
			ans = mid;
		}else{
			l = mid + 1;
		}
	}
	cout << ans << '\n';
	return ;
}

2 激光控制器

void solve(){
	int n, pos = 0;
	cin >> n;
	map<int, int> cnt;
	for(int i = 0; i < n; ++ i){
		int x;
		string c;
		cin >> x >> c;
		int l, r;
		l = r = pos;
		if(c == "L"){
			l -= x - 1;
			pos -= x - 1;
		}else{
			r += x - 1;
			pos += x - 1;
		}
		cnt[l] += 1;
		cnt[r + 1] += -1;
	}
	ll sum = 0, ans = 0, pre = 0, presum = 0;
	for(auto [x, y] : cnt){
		sum += y;
		if(presum % 4 == 1) ans += x - pre;
		pre = x;
		presum = sum;
	}
	cout << ans << '\n';
	return ;
}

3 好像相等

逐位判断对应字符是否相等时间复杂度过高,转向对每一种字符单独判断,判断每一种字符的对应位置是不是该字符
可以利用字符串哈希中的子串哈希快速完成这个判断

void solve(){
	const ll base = 131, mod = 998244353;
	int n, q;
	string ss;
	cin >> n >> q >> ss;
	vector<ll> pow(n + 1);
	vector hash(n + 1, vector<ll>(26));
	pow[0] = 1;
	for(int i = 1; i <= n; ++ i){
		for(int j = 0; j < 26; ++ j)
			hash[i][j] = (hash[i - 1][j] * base % mod + ss[i - 1] * (ss[i - 1] == 'a' + j)) % mod;
		pow[i] = pow[i - 1] * base % mod;
	}
	while(q --){
		int l1, l2, r1, r2;
		cin >> l1 >> r1 >> l2 >> r2;
		int len = r1 - l1 + 1;
		vector<char> ans;
		for(int i = 0; i < 26; ++ i){
			if((mod + hash[r1][i] - hash[l1 - 1][i] * pow[len] % mod) % mod
			   != (mod + hash[r2][i] - hash[l2 - 1][i] * pow[len] % mod) % mod)
				ans.push_back('a' + i);
		}
		cout << ans.size() << "\n";
		for(auto x : ans) cout << x;
		cout << '\n';
	}
	return ;
}

4 魔法石

void solve(){
	int n;
	cin >> n;
	vector<int> a(n);
	map<int, int> cnt;
	for(int i = 0; i < n; ++ i){
		cin >> a[i];
		cnt[a[i]] = 1;
	}
	cnt[0] = 1;
	int mx = 0, yuan = 0;
	for(auto &[d, _] : cnt){
		int sum = 0, pre = -1;
		for(auto& x : a){
			if(x == d) continue;
			if(x == pre) ++ sum;
			else{
				pre = x;
				sum = 1;
			}
			// debug2(pre, sum);
			mx = max(mx, sum);
		}
		if(d == 0) yuan = mx;
		// debug2(d, ans);
	}
	cout << mx - yuan << '\n';
	return ;
}

5 小度挪车

两遍 DFS
第一次 DFS 求解子树中的所有粉色点或所有其它颜色点到子树根所需的单位时间
第二次 DFS 求解除了当前子树以外的所有粉色点或所有其它颜色点到子树根所需的单位时间;同时可以求解答案,子树粉色点到子树根 + 别的其它颜色点到子树根 或 子树其他颜色点到子树根 + 别的粉色点到子树根的所需单位时间的最小值

void solve(){
	int n;
	string ss;
	cin >> n >> ss;
	int psize = 0, osize = 0;
	for(auto ch : ss){
		if(ch == 'P') ++ psize;
		else ++ osize;
	}
	ss = "*"  + ss;
	vector e(n + 1, vector<int>());
	for(int i = 1; i < n; ++ i){
		int u, v;
		cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	const ll INF = 0x3f3f3f3f3f3f3f3f;
	vector<ll> psz(n + 1), osz(n + 1), sz(n + 1), pdis(n + 1), odis(n + 1);
	vector<ll> fpsz(n + 1), fosz(n + 1), fpdis(n + 1), fodis(n + 1);
	ll ans = INF;
	auto dfs0 = [&](auto self, int u, int f) -> void {
		sz[u] = 1;
		if(ss[u] == 'P') ++ psz[u];
		else ++ osz[u];
		for(auto v : e[u]){
			if(v == f) continue;
			self(self, v, u);
			psz[u] += psz[v];
			pdis[u] += pdis[v] + psz[v];
			osz[u] += osz[v];
			odis[u] += odis[v] + osz[v];
			sz[u] += sz[v];
		}
		return ;
	};
	auto dfs1 = [&](auto self, int u, int f) -> void {
		for(auto v : e[u]){
			if(v == f) continue;
			fpsz[v] = psize - psz[v];
			fpdis[v] = fpdis[u] + pdis[u] - pdis[v] - psz[v] + fpsz[v];
			fosz[v] = osize - osz[v];
			fodis[v] = fodis[u] + odis[u] - odis[v] - osz[v] + fosz[v];

			if(sz[v] == psize){
				ans = min(ans, odis[v] + fpdis[v]);
			}
			if(sz[v] == osize){
				ans = min(ans, pdis[v] + fodis[v]);
			}
			self(self, v, u);
		}
		return ;
	};
	dfs0(dfs0, 1, 0);
	dfs1(dfs1, 1, 0);
	if(ans == INF) ans = -1;
	cout << ans << "\n";
	return ;
}
posted on 2023-08-12 15:14  Qiansui  阅读(776)  评论(0编辑  收藏  举报