牛客周赛98

A题

知识点:思维题

联想截图_20250629230734

首先有一个知识点:奇数没有偶因子,那么如果是奇数,加上一个自己的因子的话,那么一定会变成偶数;而偶数有奇因子1,所以一定可以在恰好操作一次的情况下变成奇数。

所有对于\(x\),我们直接判奇偶性即可。如果\(x\)为奇数,输出No;否则输出Yes


B题

联想截图_20250629231236

考察三角形的构成条件,一定是两个较小的边之和大于第三边。现在一共三条边\(x,y,z=\gcd(x,y)\),直接做法就是直接将\(x,y,z\)排序,然后判断是否\(x+y>z\)即可。

进一步可以发现,假设\(x=y\),那么\(z=\gcd(x,y)=x=y\),那么是一个等边三角形,一定能构成三角形;如果\(x \not= y\),假设\(x<y\),那么一定有\(z=\gcd(x,y)=\gcd(x,y-x) \leq \min(x,y-x)\),那么\(x+z=x+\gcd(x,y)=x+\gcd(x,y-x) \leq x+\min(x,y-x)\),当且仅当\(y=kx\)\(k>1\))下可以去等号。那么如果\(x\leq y-x\),即\(x+x\leq y\),此时有\(z=gcd(x,y-x) \leq x\),那么\(x+z\leq x+x \leq y\),不能构成三角形;如果\(x>y-x\),那么\(z=\gcd(x,y)\leq y-x\)\(x+z\leq x+y-x \leq y\),所以还是不能构成三角形,因此可以发现当\(x \not = y\)时,是无法构成三角形的。


C题

知识点:贪心

联想截图_20250629232849

就是一个非常简单的贪心,考虑\(s[i]==s[i-1]\),那么肯定是修改\(s[i]\)使得\(s[i]\not = s[i-1]\),同时\(s[i]\)修改的值尽量不要影响后面的,这里是可以的,因为\(s[i-1]\)\(s[i+1]\)最多只会占两个字符,所以完全可以选择一个和\(s[i-1]\)\(s[i+1]\)都不同的字符,所以这样贪心肯定是正确的。注意细节处理即可。

时间复杂度为\(O(n)\)

#include<bits/stdc++.h>
using namespace std;
#define inf 1e18
#define endl '\n'
#define int long long
typedef  long long ll;
typedef pair<int,int> pii;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
const int maxn=2e5+9,mod=1e9+7;
vector<string> w={"re","rd","ed","er","de","dr"};
vector<char> m={'d','e','r','d','r','e'};
char get(char c){
	if(c=='r'){
		return 'e';
	}else if(c=='e'){
		return 'd';
	}else{
		return 'r';
	}
}
void solve(){
	int n;cin >> n;
	string s;cin >> s;
	if(n<=2){
		if(n==1) cout << s << endl;
		if(n==2){
			if(s[0]!=s[1]){
				cout << s << endl;
			}else{
				s[1]=get(s[0]);
				cout << s << endl;
			}
		}
		return;
	}
	//如果n大于等于3
	int cnt=0;
	for(int i=1;i<n-1;i++){
		if(s[i]==s[i-1]){
			if(s[i-1]==s[i+1]){
				s[i]=get(s[i-1]);
			}else{
				for(int j=0;j<6;j++){
					string t=w[j];
					if(s[i-1]==t[0]&&s[i+1]==t[1]){
						s[i]=m[j];
					}
				}
			}
			cnt++;
		}
	}
	if(s[n-1]==s[n-2]){
		s[n-1]=get(s[n-2]);
		cnt++;
	}
//	cout << cnt << endl;
	cout << s << endl;
}
/*

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

D题

知识点:dfs搜索+回溯

联想截图_20250629233531

一看\(n\leq20\),又要所有满足要求的好数组,那么就想到用dfs搜索,dfs函数维护两个变量remainpre,分别表示当前还剩多少以及上一个选择的数,然后开一个vector<int> path记录每次选择的数就好了,当遇到remain=0时,输出path

vector<int> a;
void dfs(int remain,int pre){
	if(remain==0){
		for(int v:a){
			cout << v << " ";
		}
		cout << endl;
		return;
	}
	for(int i=1;i<=remain;i++){
		if(i!=pre){
			a.push_back(i);
			dfs(remain-i,i);
			a.pop_back();
		}
	}
}
void solve(){
	int n;cin >> n;
	dfs(n,0);
}

E题

知识点:gcd

联想截图_20250629234144

我们看到最大的权值子序列的权值由选择的序列的gcd和序列和sum确定,由于\(1\leq a_i \leq 10^6\),我们考虑枚举\(gcd\),我们需要先求出每个\(gcd\)能够包含的最大的子序列的和sum。令\(G\)为整个数组的\(gcd\),这个肯定是最小的,\(mx\)\(\max_{i=1}^{n}{a_i}\),这样我们确定了\(gcd\)的枚举范围,再开一个\(sum[mx+1]\)记录每个\(gcd\)对应的最大序列的和。之后枚举每一个数\(a_i\),再枚举\(gcd\),如果\(a_i\%gcd==0\),那么\(sum[gcd]+=a[i]\),最后枚举\(gcd\),取\(ans=\max_{j=G}^{mx}{j \times sum[j]}\)。但是这样要超时,时间复杂度为\(O(n\times mx)\),最坏情况下会到\(O(n^2)\),所以需要改善一下,考虑到如果我们直接枚举每个数的因数,对于\(a_i \leq 10^6\),我们会花\(O(\sqrt{a_i})\)的时间,那么最终时间复杂度优化到\(O(n\times \sqrt{mx})\),这样是可以接受的,同时我们还可以开一个map记录每一个数出现的次数,对于同样的数,我们不必多次求它的因数,所以最后做法如下:

#include<bits/stdc++.h>
using namespace std;
#define inf 1e18
#define endl '\n'
#define int long long
typedef  long long ll;
typedef pair<int,int> pii;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
const int maxn=2e5+9,mod=1e9+7;

// 生成一个数的所有因子
vector<int> generateFactors(int x) {
	vector<int> factors;
	for (int i = 1; i * i <= x; ++i) {
		if (x % i == 0) {
			factors.push_back(i);
			if (i != x / i) factors.push_back(x / i);
		}
	}
	return factors;
}

void solve(){
	int n; cin >> n;
	unordered_map<int, int> cnt;
	int mx = 0;
	int G = 0;
	
	for(int i = 0; i < n; ++i) {
		int x; cin >> x;
		cnt[x]++;
		mx = max(mx, x);
		G = __gcd(G, x);
	}
	
	vector<int> sum(mx + 1, 0); 
	
	// 遍历每个唯一的数,生成其因子并更新sum
	for (auto [x, c] : cnt) {
		vector<int> factors = generateFactors(x);
		for (int f : factors) {
			sum[f] += x * c;
		}
	}
	
	int ans = 0;
	// 枚举所有可能的gcd,从G到mx
	for (int j = G; j <= mx; ++j) {
		ans = max(ans, j * sum[j]);
	}
	
	cout << ans << endl;
}

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

F题

知识点:数学,等比数列

联想截图_20250630000020

这个还没来得及补,等后面推一下公式再写。

posted @ 2025-06-30 00:03  alij  阅读(27)  评论(0)    收藏  举报