Educational Codeforces Round 93 (ABCD题解)

                               A

在这里插入图片描述
在这里插入图片描述
题意:
给你一个递增的有序数组,问你是否存在一种情况(在这个数组里选三个数,使这三个数不可以构成三角形)。若存在,输出三个数得下标,否则输出-1。
思路:贪心,直接考虑极限情况a[1],a[2],a[n]是否满足条件即可,因为此时不满足即一定不会有满足条件得情况出现。

                             B

在这里插入图片描述
在这里插入图片描述
题意:

Alice 和 Bob 玩游戏,给他们一个只包含 1 和 0 得字符串 ,他们轮流操作,Alice 先手。
每个人每次可以选择拿掉连续的 x (x>=1) 个 0或1,每个人的得分是他们拿掉的1的数量,两个人都很聪明,问Alice的最大分数。

思路:

策略:每个人都会选择当前回合所能选择最多的1的数量。
简易证明:首先每个人都不会选0,因为选0,既不会给自己做出贡献,反而有可能给对方做出贡献,然后每个人选1的话一定会把1最多的那一堆的1全部拿完。(然后这一步不是很会证明,但很容易想到)。

                            C

在这里插入图片描述
在这里插入图片描述

题意:
给你一段长度为n的字符串,字符串只包含( ‘0’ - ‘9’ ) 。
问你这里面存在多少区间 [ l,r ] 使得 sum[r] - sum[l-1] = r - l + 1 ;
思路
这个题在比赛时我想复杂了,写了一个类似滑动数组的dp,后来发现他本质上用标记数组就可以实现不用滑动,后面会附上这两种代码的实现方式,主要说一下标记数组的实现,首先 (r-l+1) = 区间 [l,r] 内点的数量,这里把a[i]映射一下,0 ~ 9 -> -1 ~ 8 。
然后题意就变成了问存在多少个区间 [l,r] 使得sum[r] - sum[l-1] = 0(即sum[r] = sum[l])。 然后这里用标记数组实现就好了。

                                D

在这里插入图片描述
在这里插入图片描述

题意:
给你三种颜色的彩带,颜色分别是红绿蓝,数量分别是l1,l2,l3;
你每次可以选择两条颜色彩带构造矩形,然后获得一个分数是他们的长度之积,然后每个彩带只能被选择一次,问你可以获得的最大分数。
思路:
这个题比较有意思,他刚开始配合样例比较隐秘的诱导你往贪心哪里想,但是绝大多数(不好随便立flag)贪心是不对的,这里提供两组样例,想用贪心的可以仔细看看这两组数据。

2 2 4
9 9
9 9
8 8 8 8

2 4 6
10 10
10 10 10 10
10 10 10 10 10 10

好了,该说正解了,我写的是dp,dp[i] [j] [k] 代表选择i个红色彩带,j个绿色彩带,k个蓝色彩带 所能获得的最大值,具体方程看代码即可。

代码:

							A
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+15;
typedef long long ll;
ll a[N];
int main()
{
    ll t,n,ans;
    cin>>t;
    while(t--)
    {
        cin>>n; ans=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        if(n<3)
        {
            cout<<"-1"<<endl;   continue;
        }
        if(a[1]+a[2]<=a[n])
        {
            cout<<"1 2 "<<n<<endl;
        }
        else
            cout<<"-1"<<endl;
    }
    return 0;
}


								B
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+15;
typedef long long ll;
ll a[N];
int main()
{
    ll t,n,ans;
    char str[N];
    cin>>t;
    while(t--)
    {
        scanf("%s",str+1);
        n=strlen(str+1);
        ans=0;
        ll op=0,cnt=0;
        str[n+1]='0';
        for(int i=1;i<=n+1;i++)
        {
            if(str[i]=='1')
                op++;
            else
            {
                if(op!=0)
                {
                    a[++cnt]=op;    op=0;
                }
            }
        }
        sort(a+1,a+1+cnt);
        for(int i=cnt;i>=1;i-=2)
        {
            ans+=a[i];
        }
        cout<<ans<<endl;
    }
    return 0;
}


							C(滑动数组dp)
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+15;
typedef long long ll;
ll dp[4000000];
int a[1000000];
char str[300000];
int main()
{
    ll t=1000,n=100,ans;

    cin>>t;
    while(t--)
    {
        cin>>n;
        scanf("%s",str+1);
        for(int i=1;i<=n;i++)
        {
            a[i]=int(str[i]-'0');
        }
        ans=2000000;
        int minl=ans;    int maxl=ans;
        for(int i=1;i<=n;i++)
        {
            ans+=a[i];
            int op=ans-i;
            minl=min(minl,op);  maxl=max(maxl,op);
            dp[op]++;
        }
        ll sum=0;
        sum+=dp[2000000];
        int l=2000000;
        for(int i=2;i<=n;i++)
        {
            ll d=a[i-1]-1;
            dp[l+d]--;  l+=d;    sum+=dp[l];
        }
        for(int i=minl-10;i<=maxl+10;i++)
            dp[i]=0;
        printf("%lld\n",sum);
    }
    return 0;
}


							C标记数组
#include <iostream>
#include <map>
using namespace std;
constexpr int kN = int(1E5 + 10);
int s[kN];
map<int, int> m;

void solve() {
	int n;
	string a;
	long long int ans = 0;
	cin >> n >> a;
	for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i - 1] - '0';
	for (int i = 1; i <= n; i++) s[i] -= i;
	m.clear();
	m[0] = 1;
	for (int i = 1; i <= n; i++) {
		if (m.find(s[i]) != m.end()) ans += m[s[i]];
		m[s[i]]++;
	}
	cout << ans << '\n';
}

int main() {
	int t;
	cin >> t;
	while (t--) solve();
}

								D
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+15;
typedef long long ll;
bool cmp(int a,int b)
{
    return a>b;
}
int a[N],b[N],c[N];
ll dp[202][202][202];
int main()
{
    ll la,lb,lc;
    cin>>la>>lb>>lc;
    for(int i=1;i<=la;i++)
        cin>>a[i];
    for(int i=1;i<=lb;i++)
        cin>>b[i];
    for(int i=1;i<=lc;i++)
        cin>>c[i];
    sort(a+1,a+1+la,cmp);
    sort(b+1,b+1+lb,cmp);
    sort(c+1,c+1+lc,cmp);
    dp[1][1][0]=a[1]*b[1];
    dp[1][0][1]=a[1]*c[1];
    dp[0][1][1]=b[1]*c[1];
    ll op1,op2,op3;
    ll ans=0;
    for(int i=0;i<=la;i++)
    {
        for(int j=0;j<=lb;j++)
        {
            for(int k=0;k<=lc;k++)
            {
                op1=0,op2=0,op3=0;
                if(i>0&&j>0)
                    op1=dp[i-1][j-1][k]+a[i]*b[j];
                if(i>0&&k>0)
                    op2=dp[i-1][j][k-1]+a[i]*c[k];
                if(j>0&&k>0)
                    op3=dp[i][j-1][k-1]+b[j]*c[k];
                op2=max(op1,op2);   op3=max(op3,op2);
                dp[i][j][k]=max(dp[i][j][k],op3);
                ans=max(ans,dp[i][j][k]);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值