Educational Codeforces Round 93

A、B、C、D四道题题解

一.A题

A题题目链接

(1)题意:

有t组测试数据,每组测试数据有n个数,且这n个数按升序输入,问这组数据里面能不能选出三个数,使他们不能凑成三角形,能就输出三个数的位置,不能就输出-1。

(2)题解:

三角形的特性是两边之和大于第三边,两边之差小于第三边。
所以我们直接判断最大的差与剩下最小的数的关系,即a[n] - a[1]与a[2]的关系,假如a[n] - a[1] < a[2]的话,说明这n个数的差距不大,并不能出现两边之差大于等于第三边,两边之和小于等于第三边的情况。
其他情况下就直接输出1,2,n即可。

(3)代码:

#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue> 
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#include<functional>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;

int a[maxn],t,n;

bool check()
{
	if(a[n] - a[1] < a[2])
		return true;
	return false;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i = 1; i <= n; i++)
			scanf("%d",&a[i]);
		//sort(a+1,a+1+n);
		
		if(check())
		{
			printf("-1\n");
		}
		else{
			printf("%d %d %d\n",1,2,n);
		}
	}
	return 0;
}

二.B题

B题题目链接

(1)题意:

给t组数据,每组数据有一个字符串s,字符串由‘0’和‘1’组成。Alice和Bob玩游戏,Alice先走,每次可以选择不少于1的任意长度的连续相等字符,然后消除掉:
例如 110011,可以选择[1,2] -> 0011,也可以选择[3,4] -> 1111
每次选择了一个1,就加一分,问都选择最优策略的情况下,Alice最多可以获得多少分?

(2)题解:

因为是交错选择,所以选择连续的‘0’是不理智的行为,这样的话就会让Bob一次选择到更多的‘1’,同样的Bob也不会做这样的行为,所以就是每次选择当前最多连续‘1’。
统计出所有连续的‘1’,然后排个序,在交叉选择,就是Alice的最多可获取的分数。

(3)代码:

#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue> 
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#include<functional>

using namespace std;

typedef long long ll;
const int maxn = 1e4 + 10;
const int INF = 0x3f3f3f3f;

int t,a[maxn];

bool cmp(int x,int y)
{
	return x > y;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		memset(a,0,sizeof(a));
		int flag = 0,cnt = 0,ans = 0;
		string str;
		cin>>str;
		for(int i = 0; i < str.size(); i++)
		{
			if(str[i] == '1' && flag == 0)
			{
				cnt++;
				flag++;
			}
			else if(str[i] == '1' && flag != 0)
			{
				flag++;
			}
			else if(str[i] == '0' && flag != 0)
			{
				a[cnt] += flag;
				flag = 0;
			}
		}
		if(flag != 0)
			a[cnt] = flag;
			
		sort(a+1,a+1+cnt,cmp);
		
		for(int i = 1; i <= cnt; i++)
		{
			if(i % 2 == 1)
				ans += a[i];
		}
		
		printf("%d\n",ans);
	}
	return 0;
}

三.C题

C题题目链接

(1)题意:

有t组测试数据,每组数据有n个数,这些数连续输入且每个数的大小在‘0’~‘9’之内,问有多少个子串满足a[l] + a[l+1] ……+a[r] = r- l + 1?

(2)题解:

首先要知道每当连续遇到一个满足条件的值的时候,ans是当前数的累加,例如1111 -> ans = 1+2+3+4;
其次每当遇见一个大于1的数 a[i] 就得向前或者向后寻找到a[i] - 1个0才能又满足条件;同理遇到一个0也是一样的;
所以我们把所有值-1,这样1 -> 0就不会影响我们维护的前缀值,然后 0 -> -1就代表需要向前或者向后找到1来填补,在这个过程中我们来维护前缀值。

(3)代码:

#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue> 
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#include<functional>

using namespace std;

typedef long long ll;
const int maxn = 1e2 + 10;

int t,n;

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		ll k = 0, ans = 0;
		
		map<int,int> sum;
		
		sum[0] = 1;
		
		for(int i = 0; i < n; i++)
		{
			char ch;
			scanf(" %c",&ch);
			k += ch - '0' - 1;
			
			ans += sum[k];
			sum[k]++;
			//这里sum[k]++是因为有类似于500005这样的情况,向前向后填坑都是满足条件
			//所以ans不单单只加上 sum = 0的时候
		}
		
		printf("%lld\n",ans);
	}
	return 0;
}

四.D题

D题题目链接

(1)题意:

有三种颜色的木棍分别有各R、G、B对,每次选择两对不同颜色的木棍组成一个矩形,问所有能组成的矩形面积之和是多少

(2)题解:

因为R、G、B都不超过200,所有三重for循环的dp是满足的,下面确定各个变量与状态转移方程:
r[i] : 第一种颜色的第 i 对木棍长度
g[i] : 第二种颜色的第 i 对木棍长度
b[i] : 第三种颜色的第 i 对木棍长度
dp[i][j][k]:前 i 对 r ,前 j 对 g ,前 k 对 b的最大值
每次当 i >= 1 && j >= 1 说明 i ,j 可取,dp[i][j][k] = max(dp[i][j][k] , dp[i-1][j-1][k] + r[i] * g[j]);
同理剩下 i >= 1 && k >= 1 和 j >= 1 && k >= 1也是一样的。

(3)代码:

#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue> 
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
#include<functional>

using namespace std;

typedef long long ll;
const int maxn = 2e2 + 10;

ll r[maxn], g[maxn], b[maxn];
ll dp[maxn][maxn][maxn];
int R,G,B;

int main()
{
    scanf("%d%d%d",&R,&G,&B);
    
    for(int i = 1; i <= R; i++)
    	scanf("%lld",&r[i]);
    for(int i = 1; i <= G; i++)
    	scanf("%lld",&g[i]);
    for(int i = 1; i <= B; i++)
    	scanf("%lld",&b[i]);

    sort(r+1, r+1+R);
    sort(g+1, g+1+G);
    sort(b+1, b+1+B);

    for(int i = 0; i <= R; ++i){
        for(int j = 0; j <= G; ++j){
            for(int k = 0; k <= B; ++k){
                if(i&&j)
					dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k] + r[i]*g[j]);
                if(j&&k)
					dp[i][j][k] = max(dp[i][j][k], dp[i][j-1][k-1] + g[j]*b[k]);
                if(i&&k)
					dp[i][j][k] = max(dp[i][j][k], dp[i-1][j][k-1] + r[i]*b[k]);
            }
        }
    }

    printf("%lld\n",dp[R][G][B]);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值