2022-05-27测试

神奇的字符串

这个题晃眼一看,其实就可以知道,是一个比较简单的DP问题。我们设dp[i]表示一直到第 个字母为止 时所能得到的最长神奇字符串的长度。那么,如果第 个字母不在我们最终的最长神奇字符串当中,可以 得到dp[i]=dp[i-1],如果第 个字母在最长神奇字符串当中,那么,这个字母肯定会和最近一个和它相同的 字符进行匹配,记这个位置为pre[s[i]],因此,可以得到dp[i]=max(dp[i1],dp[pre[s[i]-1]]+2) 当然,我们再想一下,这个题就真的只能用DP来解决么?通过分析,我们可以知道,因为我们要得到尽 可能长的满足条件的字符串,那么,就需要尽可能多的添加满足条件的一对字符,因此,我们就可以利 用贪心的思想,给每一个找过的字母打上标记,如果我们发现当前字母在前面的标记中已经出现过了, 那么,我们就让答案+2,并清0所有标记,因为只有这样,我们才可以添加数量尽可能多的字母到字符 串当中。

#include <bits/stdc++.h>
using namespace std;
string s;
int mp[30];
int main() {
	int t;
	scanf("%d",&t);
	while(t--){
		memset(mp,0,sizeof(mp));
		cin>>s;
		int len=s.length(),m=0;
		for(int i=0;i<len;i++){
			if(mp[s[i]-'a']){
				m+=2;
				memset(mp,0,sizeof(mp));
			}
			else{
				mp[s[i]-'a']=1;
			}
		}
		printf("%d\n",len-m);
	}
	return 0;
}

海盗游戏

对于这个题,我们的最优解肯定是让自己尽可能多的取偶数,而让对手去取奇数。很明显,我们选取金 币的方案跟我们除以4得到的余数是几有关。 如果得到的余数是1或者是3,说明当前金币的数量是奇数,那没办法,我们只能从中取出1枚金币。 如果除以4的余数是2,很明显,这时我们如果取了一半,那么剩下的数就会是一个奇数,这时,我们就 取一半。 如果除以4的余数是0,这时,如果我们取了一半,那么,约翰也能取一半。如果这时我们只取1枚金 币,那么,约翰也只能取1枚金币,这样,我们下次取时,就可以保证我们取完一半之后,约翰也只能取 1枚金币(回到了除以4的余数是2的情况),因此,这时,我们也只取1枚金币(金币数等于4时除外)。 这样,我们就可以得到尽可能多的金币了。

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        long long a[2] = {}, u = 0, n;
        scanf("%lld", &n);
    while (n) {
        if (n % 2 == 0 && ((n / 2) % 2 || n == 4))
            a[u % 2] += n / 2, n /= 2;
        else
            n--, a[u % 2]++;
            u++;
        }
        printf("%lld\n", a[0]);
    }
}

五子棋盘

这个题是一个比较简单的模拟题。因为每一步棋的位置是确定的,那么,当我们添加一枚棋子以后,就 可以去判断,在当前状态之下,有没有人获得了整场比赛的胜利(即出现了连成5个的情况)。因为出现新 的胜利情况,肯定会和我们新下的这枚棋子有关,因此,我们只需要找与我们新下的这枚棋子成米字型 的这样一个区域的内容即可。

#include <bits/stdc++.h>
int n, a[20][20];
bool check(int x, int y, int z) { 
	a[x][y] = z;
	int i = x + 1, j = y + 1, s = 1;
	while (i < 16 && j < 16 && s < 5 && a[i][j] == z) ++s, ++i, ++j; 
	if (s == 5)
		return 1;
	i = x - 1,j=y-1;
	while (i && j && s < 5 && a[i][j] == z) ++s, --i, --j; 
	if (s == 5)
		return 1;
	i = x + 1,j=y-1,s=1;
	while (i < 16 && j && s < 5 && a[i][j] == z) ++s, ++i, --j; 
		if (s == 5)
			return 1;
	i = x - 1,j=y+1;
	while (i && j < 16 && s < 5 && a[i][j] == z) ++s, --i, ++j;
		if (s == 5)
			return 1;
	j = y - 1,s=1;
	while (j && s < 5 && a[x][j] == z) ++s, --j; 
		if (s == 5)
			return 1;
		j = y + 1;
	while (j < 16 && s < 5 && a[x][j] == z) ++s, ++j; 
		if (s == 5)
			return 1;
	i = x - 1,s=1;
	while (i && s < 5 && a[i][y] == z) ++s, --i; 
	if (s == 5)
	return 1;
	i = x + 1;
	while (i < 16 && s < 5 && a[i][y] == z) ++s, ++i;
		if (s == 5)
			return 1;
	return 0;
}
int main() {
	memset(a, -1, sizeof(a));
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		if (check(x, y, i & 1)) {
			printf("%c %d", (i & 1 ? 'A' : 'B'), i);
			return 0;
		}
	}
	printf("Tie");
	return 0;
}

能量石

对于这个题而言,解决问题的关键在于如果去处理这个能量消耗的问题。对于任意两个能量石x、y而 言,我们吃掉这两个石头能够得到的能量就为max(x.e+y.e-x.s*y.l , x.e+y.e-y.s*x.l),其中e表示初始能 量,l表示每秒损失的能量,s表示吃掉这个物品所消耗的时间。因此,我们就可以根据这一公式对所有 的石头进行排序,越靠前的石头对整个计算能量消失的比重就越大,就越先进行计算。然后,再将总的 时间看成背包的体积,每个物品的价值看成价值,对这个题进行01背包计算,最终就可以得到答案。

#include<bits/stdc++.h>
using namespace std;
int dp[10005];
struct node{
	int s,e,l;
}arr[105];
bool cmp(node x,node y){
	return x.s * y.l < y.s * x.l;
}
int main(){
	int t,n,q=0;
	scanf("%d",&t);
	while(t--){
		memset(dp,0,sizeof(dp));
		q++;
		int m=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d%d%d",&arr[i].s,&arr[i].e,&arr[i].l);
			m+=arr[i].s;
		}
		sort(arr+1,arr+n+1,cmp);
		for(int i=1;i<=n;i++){
			for(int j=m;j>=arr[i].s;j--){
				dp[j]=max(dp[j],dp[j-arr[i].s]+max(0,arr[i].e-arr[i].l*(j-arr[i].s)));
			}
		}
		int ans=0;
		for(int i=0;i<=m;i++){
			ans=max(ans,dp[i]);
		}
		printf("Case #%d: %d\n",q, ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值