Week 15

文章包含了多个编程算法问题的解题思路和代码实现,包括检查字符串是否能通过删除字符变为回文串、计算数组区间内乘积的最大平方和、判断两个数乘以2或3后能否相等以及找出字符串的所有子串中不同字符的计数和。这些问题主要涉及字符串处理、动态规划和数学算法的应用。
摘要由CSDN通过智能技术生成

代码源每日一题Div2

305. 删删

原题链接:删删

思路:直接遍历从a到z的所有字母,依次判断只删除这些字母能不能构成回文串,并取构成回文串时删除的字符的最小值。具体地,用两个指针分别指向字符串的头和尾,然后向中间移动指针,如果遇到相应的字母且两指针处的字符不相等则跳过该字符,直到两指针相遇时如果指针所指的字符均相等则说明能构成回文串。

代码:

#include <bits/stdc++.h>
using namespace std;
int t, n, ans;
string s;
int main(){
	cin >> t;
	for(int i = 0; i < t; i++){
		cin >> n >> s;
		ans = 0x3f3f3f3f;
		bool flag = false;
		for(int j = 'a'; j <= 'z'; j++){
			int l = 0, r = n - 1, tmp = 0;
			bool flag1 = true;
			while(l < r){
				if(s[l] != s[r]){
					if(s[l] == j) l++, tmp++;
					else if(s[r] == j) r--, tmp++;
					else{
						flag1 = false;
						break;
					}
				}
				else l++, r--;
			}
			if(flag1) ans = min(ans, tmp), flag = true;
		}
		if(!flag) cout << -1 << endl;
		else cout << (ans == 0x3f3f3f3f ? 0 : ans)<< endl;
	}
	return 0;
}

306. 快快变大

原题链接:快快变大

思路:区间dp,先对数组中连续的乘积预处理,用mul[i][j]表示从ai乘到aj的乘积,然后直接套用区间dp模板:

dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + (mul[i][k] - mul[k + 1][j]) * (mul[i][k] - mul[k + 1][j]));

其中dp[i][j]表示ai到aj区间的最大分数。

代码:

#include <bits/stdc++.h>
using namespace std;
long long n, a[500], dp[500][500], mul[500][500];
int main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		mul[i][i] = a[i];
		for(int j = 1; j < i; j++){
			mul[j][i] = (mul[j][i - 1] * a[i]) % 1000003;
		}
	}
	for(int len = 2; len <= n; len++){
		for(int i = 1; i + len - 1 <= n; i++){
			int j = i + len - 1;
			for(int k = i; k < j; k++){
				dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + (mul[i][k] - mul[k + 1][j]) * (mul[i][k] - mul[k + 1][j]));
			}
		}
	}
	cout << dp[1][n];
	return 0;
}

307. 饿饿 饭饭2

原题链接:饿饿 饭饭2

思路:如果两个数乘上2或3能变成一个相同的数,那么反过来想,用这个相同的数一直除2或3,那么最后一定能除成一个不能被2和3整除的数,说明这两个数分别除2或3也能除成一个相同的且不能被2和3整除的数。按照次思路写代码即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int t, n, a[200005];
int main(){
    cin >> t;
    for(int i = 0; i < t; i++){
    	cin >> n;
    	bool flag = true;
    	for(int j = 1; j <= n; j++){
    		cin >> a[j];
		}
		for(int j = 1; j <= n; j++){
			while(a[j] % 2 == 0 || a[j] % 3 == 0){
				if(a[j] % 2 == 0) a[j] /= 2;
				if(a[j] % 3 == 0) a[j] /= 3;
			}
		}
		for(int j = 1; j < n; j++){
			if(a[j] != a[j + 1]){
				flag = false;
				break;
			}
		}
		if(flag) cout << "YES\n";
		else cout << "NO\n";
	}
    return 0;
}

401. 子串分值和

原题链接:子串分值和

思路:依题意,所有子串中出现的不同字符的数量即为所有包含某一种字符的子串的总和,求出所有的只包含某一种字符的子串数量即可。

代码:

#include <bits/stdc++.h>
using namespace std;
string s;
long long ans;
int main(){
    cin >> s;
    for(int i = 'a'; i <= 'z'; i++){
    	long long len = 0, tmp = 0;
    	for(int j = 0; j < s.size(); j++){
    		if(s[j] == i){
    			tmp += len * (len + 1) / 2;
    			len = 0;
			}
    		else len++;
		}
		tmp += len * (len + 1) / 2;
		ans += s.size() * (s.size() + 1) / 2 - tmp;
	}
	cout << ans;
    return 0;
}

402. 蒟蒻

原题链接:蒟蒻

思路:用两个map存储果冻的价格与口感,分别为map<价格,口感>,map<口感,价格>,则操作1为给map容器赋值,操作2和操作3为用map中begin()方法取出第一个元素,判断重复时使用count()方法即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int n, ans;
map<int, int> mp1, mp2;
int main(){
	cin >> n;
    for(int i = 0; i < n; i++){
    	int op;
    	cin >> op;
    	if(op == 1){
    		int w, t;
    		cin >> w >> t;
    		if(mp1.count(w) == 0 && mp2.count(t) == 0) mp1[w] = t, mp2[t] = w;
		}
		else if(op == 2){
			mp2.erase(mp1.begin()->second);
			mp1.erase(mp1.begin()->first);
		}
		else if(op == 3){
			mp1.erase(mp2.begin()->second);
			mp2.erase(mp2.begin()->first);
		}
	}
	for(auto w : mp2){
		ans += w.second; 
	}
	cout << ans;
    return 0;
}

403. 锦标赛

原题链接:锦标赛

思路:由题意,两者能力值之差大于k时则能力值高的人必胜,若差值小于等于k则都有可能获胜,那么对于以能力值排序后的数组,从能力值最大的人开始遍历,如果有俩人能力值之差大于k,则从这两人中能力值低的人开始,往后的能力值更低的人则不可能获胜。此时可能获胜的人即为前面的所有人。

代码:

#include <bits/stdc++.h>
using namespace std;
int n, k, a[100005], ans;
bool check(int i, int j){
	return fabs(a[i] - a[j]) <= k;
}
int main(){
    cin >> n >> k;
    for(int i = 1; i <= n; i++){
    	cin >> a[i];
	}
	sort(a + 1, a + 1 + n);
	for(int i = n; i > 1; i--){
		if(check(i, i - 1)) ans++;
		else break;
	}
	cout << ans + 1;
    return 0;
}

404. 可重排列

原题链接:可重排列

思路:简单的dfs,回溯条件为输出的总数达到p1 + p2 + … + pn。

代码:

#include <bits/stdc++.h>
using namespace std;
int n, a[10], tmp[100], sum;
void dfs(int cnt){
	if(cnt == sum){
		for(int i = 0; i < cnt; i++) printf("%d ", tmp[i]);
		printf("\n");
		return;
	}
	for(int k = 1; k <= n; k++){
		if(a[k]){
			a[k]--;
			tmp[cnt] = k;
			dfs(cnt + 1);
			a[k]++;
		}
	}
	return;
}
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++){
    	cin >> a[i];
    	sum += a[i];
	}
	dfs(0);
    return 0;
}

405. 进制转换

原题链接:进制转换

思路:简单地模拟进制的转换过程即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int n, m;
long long sum;
string ans = "";
int main(){
    cin >> n >> m;
    for(int i = 0; i < n; i++){
    	int t, tmp = 0;
    	string x;
    	cin >> t >> x;
    	for(int j = 0; j < x.size(); j++){
    		if(x[j] >= '0' && x[j] <= '9') tmp = tmp * t + (x[j] - '0');
    		else if(x[j] >= 'A' && x[j] <= 'Z') tmp = tmp * t + (x[j] - 'A' + 10);
    		else if(x[j] >= 'a' && x[j] <= 'z') tmp = tmp * t + (x[j] - 'a' + 36);
		}
		sum += tmp;
	}
	while(sum){
		int tmp = sum % m;
		if(tmp <= 9) ans.push_back(tmp + '0');
		else if(tmp >= 10 && tmp <= 35) ans.push_back(tmp - 10 + 'A');
		else if(tmp >= 36 && tmp <= 61) ans.push_back(tmp - 36 + 'a');
		sum /= m;
	}
	reverse(ans.begin(), ans.end());
	cout << ans;
    return 0;
}

406. 循环子串

原题链接:循环子串

思路:由题意,如果一个字符串的所有子串的倒转串均为原字符串的循环子串并且这个字符串的最长子串(即字符串本身)的倒转串也为原字符串的循环子串,那么该最长子串的所有子串一定也为原字符串的循环子串。因此只需要判断字符串本身的倒转串是否为原字符串的循环子串即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int t, n;
string s;
int main(){
    cin >> t;
    for(int i = 0; i < t; i++){
    	cin >> n >> s;
    	string tmp = s;
    	reverse(tmp.begin(), tmp.end());
    	bool flag = false;
    	for(int j = 0; j < n; j++){
    		char ch = s[n - 1];
    		for(int k = n - 1; k >= 1; k--){
    			s[k] = s[k - 1];
			}
			s[0] = ch;
			if(tmp == s){
				flag = true;
				break;
			}
		}
		if(flag) cout << "YES\n";
		else cout << "NO\n";
	}
    return 0;
}

407. 饿饿 饭饭之暑假大狂欢

原题链接:饿饿 饭饭之暑假大狂欢

思路:最有益于某个人的策略即为每次抽出的球的数字都为某个人手里的数字,那么直接遍历所有人,并判断划掉所有的数字时其他人有没有划完所有数字即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int t, n, a;
vector<int> vec[105];
bool vis[105][105];
int main(){
    cin >> t;
    for(int i = 1; i <= t; i++){
    	cin >> n;
    	for(int j = 0; j < n; j++){
    		cin >> a;
    		vec[i].push_back(a);
    	}
	}
	for(int i = 1; i <= t; i++){
		bool flag = true;
		memset(vis, 0, sizeof(vis));
		for(int j = 1; j <= t; j++){
			if(j == i) continue;
			int sum = 0;
			for(int k = 0; k < vec[i].size(); k++){
				for(int h = 0; h < vec[j].size(); h++){
					if(vec[i][k] == vec[j][h] && !vis[j][h]){
						sum++; 
						vis[j][h] = true;
					}
				}
			}
			if(sum == vec[j].size()){
				flag = false;
				break;
			}
		}
		if(flag) cout << "YES\n";
		else cout << "NO\n";
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值