Educational Codeforces Round 115 (Rated for Div. 2)部分题解(A~D)

39 篇文章 1 订阅


前言

我还记得,当年我也是一个平均学分绩点可以达到4的好学生。
现在博主已经变成了平均学分绩点在3~3.5徘徊的fw了,但主不在乎

在这里插入图片描述

从现在开始,一并超!(每周至少1篇并且超量完成)

在这里插入图片描述

吐槽一下,夜王在权游里整整铺垫了3季还要多,又是异鬼军团又是转化冰龙,结果boss战里二丫只用了11秒就单杀了夜王。(从夜王拔剑开始,到二丫把刀刺进夜王身体,11s)
跟我预想中的boss战差了亿点点,不过还是很不错的。

下图为免疫龙焰的歪嘴屑夜王,一个明明可以猥琐在后面施法复活队友拿下胜利却有着上单的胆子冲到人家法师面前结果被敌方刺客11秒刀死的不死族法师。
在这里插入图片描述


A. Computer Game(思维+水题)

比赛链接:https://codeforces.com/contest/1598/problem/A

题目大意

M o n o c a r p Monocarp Monocarp正在玩一款游戏,现在他进入了游戏的第一关。
这一关是一个 2 2 2 n n n列的迷宫,迷宫里 0 0 0代表可以走, 1 1 1代表不可以走。 M o n o c a r p Monocarp Monocarp所控制的角色处于 ( 1 , 1 ) (1,1) (1,1)格,终点在 ( 2 , n ) (2,n) (2,n)格。
角色每次移动时需要满足:
初 始 位 置 : ( x 1 , y 1 ) , 目 的 位 置 : ( x 2 , y 2 ) , ∣ x 1 − x 2 ∣ < = 1 并 且 ∣ y 1 − y 2 ∣ < = 1 。 初始位置:(x_1,y_1),目的位置:(x_2,y_2),|x_1-x_2|<=1 并且 |y_1-y_2|<=1。 :(x1,y1):(x2,y2)x1x2<=1y1y2<=1

现在问你, M o n o c a r p Monocarp Monocarp是否可以通关?

思路

又是一个为数不多的在奇怪时间点开始的比赛。
看到这题的时候脑子犯抽,想的是直接用 B F S BFS BFS搜就完事了。

结果刚开始敲 B F S BFS BFS函数的时候突然想到:这好像只是一个简单的思维题吧。
为了防止掉大分,博主当时就跑路了。

结果跟我想的一样,压根就不用搜索。 M o n o c a r p Monocarp Monocarp在向右边前进的过程中,假设他现在在 ( 1 , j ) (1,j) (1,j),根据条件限制我们可以推断出,只有一种情况可以阻碍他前进到下一列:(1,j+1)==1 && (2,j+1)==1
所以我们只需要找有没有一列的数字都是1的情况,有的话 M o n o c a r p Monocarp Monocarp就没法通关了

推出以上结论的关键是看懂人物的移动方式

AC代码

#include<bits/stdc++.h>

using namespace std;

const long long mod=1e9+7;

string ss[3];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        string flag="YES";
        cin>>ss[0]>>ss[1];
        for(int i=0;i<n;i++)
        if(ss[0][i]==ss[1][i]&&ss[1][i]=='1'){
            flag="NO";
            break;
        }
        cout<<flag<<endl;
    }
}

B. Groups(暴力+水题)

比赛链接:https://codeforces.com/contest/1598/problem/B

题目大意

现在你得到了一个二维数组 a a a,用于表示 n n n( n n n一定是偶数)个同学一周的课程情况。
a [ i ] [ j ] = = 0 a[i][j]==0 a[i][j]==0,则说明学生 i i i在周 j j j那一天有课;若 a [ i ] [ j ] = = 1 a[i][j]==1 a[i][j]==1,则说明学生 i i i在周 j j j那一天没课。
现在老师想要给这 n n n个人分成两批进行补课,两批学生的人数相同,每个学生只补一次课。学生只有在没课的那天才能接受补课。
老师想知道他是否可以找到合适的两天给学生补课。

思路

一开始没太看懂,主要是有一点点的绕。

我们暴力枚举出补课的日期 i 、 j i、j ij,然后将所有学生分为 4 4 4种:
1 1 1.可以在第 i i i天补课,也可以在第 j j j天补课;
2 2 2.可以在第 i i i天补课,不可以在第 j j j天补课;
3 3 3.不可以在第 i i i天补课,可以在第 j j j天上补课;
4 4 4.不可以在第 i i i天补课,不可以在第 j j j天补课;

那么补课日期 i 、 j i、j ij可以被选用的条件就是:没有第 4 4 4种学生,第 2 2 2种学生与第 3 3 3种学生的数量都小于等于 n / 2 。 n/2。 n/2

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int arr[1050][10];

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=5; j++)
                cin>>arr[i][j];
        }

        string flag="NO";
        for(int i=1; i<=5; i++)
        {
            for(int j=i+1; j<=5; j++)
            {
                int a=0,b=0,c=0,d=0;
                for(int k=1; k<=n; k++)
                {
                    if(arr[k][i]==0&&arr[k][j]==0)
                        a++;
                    if(arr[k][i]==0&&arr[k][j]==1)
                        b++;
                    if(arr[k][i]==1&&arr[k][j]==0)
                        c++;
                    if(arr[k][i]==1&&arr[k][j]==1)
                        d++;
                }
                if(a==0&&b<=n/2&&c<=n/2)
                {
                    flag="YES";
                    break;
                }
            }
            if(flag=="YES") break;
        }


        cout<<flag<<endl;
    }
}

C. Delete Two Elements(数学公式转换)

比赛链接:https://codeforces.com/contest/1598/problem/C

题目大意

我们把一个数组所有数的和 s u m sum sum除以数组长度 n n n的值 s u m / n sum/n sum/n记作 k k k

现在我要在数组中随便删除两个数字 a i ai ai a j aj aj,数组的 k k k会变成 k ′ k' k
请问我可以找到多少对不同的 ( i , j ) (i,j) (i,j),使得我删掉 a i ai ai a j aj aj之后, k ′ k' k仍然等于 k k k

思路

一开始我还以为是个数论,仔细看了看之后发现是老朋友——公式转换。
我们把题目中描述的公式写出:
s u m / n = = [ s u m − ( a i + a j ) ] / ( n − 2 ) sum/n==[sum-(a_i+a_j)]/(n-2) sum/n==[sum(ai+aj)]/(n2)

除法这个东西只要不是整除,就一定会出现浮点数,而浮点数就很容易出现精度问题。
所以我们需要改一下式子,要乘不要除
= > s u m ∗ ( n − 2 ) = = [ s u m − ( a i + a j ) ] ∗ n =>sum*(n-2)==[sum-(a_i+a_j)]*n =>sum(n2)==[sum(ai+aj)]n
= > s u m ∗ 2 = = ( a i + a j ) ∗ n =>sum*2==(a_i+a_j)*n =>sum2==(ai+aj)n

此时问题就简单了:在数组中找有多少对数字相加满足 s u m ∗ 2 = = ( a i + a j ) ∗ n sum*2==(a_i+a_j)*n sum2==(ai+aj)n即可。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    int t,n;
    cin>>t;
    while(t--)
    {
        ll sum=0,x;
        int n;
        cin>>n;
        //if(n==200000) getdata();
        map<ll,int> mp;
        for(int i=0; i<n; i++)
        {
            cin>>x;
            sum+=x;
            mp[x]++;
        }
        map<ll,int>::iterator it;
        ll ans=0;
        for(it=mp.begin(); it!=mp.end(); it++)
        {
            //cout<<it->first<<endl;
            int y=2*sum/n-(it->first);
            if(mp[y])
            {
                if(((it->first)+y)*n==sum*2)
                {
                    if(y==it->first) ans+=(1LL)*(it->second)*(it->second-1)/2; 
                    else ans+=(1LL)*(it->second)*mp[y]; //1LL的原因是在第8个样例中,(it->second)*mp[y]爆出了int的范围,所以强转一下
                    it->second=0;
                }
            }
        }
        cout<<ans<<endl;
    }
}

D. Training Session(逆向思维+map活用+排列组合)

比赛链接:https://codeforces.com/contest/1598/problem/D

题目大意

给出n对 ( a i , b i ) (ai,bi) (ai,bi),你现在需要在这 n n n对中挑出三个,这三个 ( a i , b i ) (ai,bi) (ai,bi)需要至少满足下述条件中的一个:

  • 三个 a a a互不相同
  • 三个 b b b互不相同

问可以找到多少个符合条件的三元组。

思路

正着做不是很好做,我们反着来,就是用所有的情况减去不符合的情况。
所有情况的数量: C n 3 C_{n}^{3} Cn3

不符合条件的数量求起来其实也很简单,既然要求上说 3 3 3 ( a i , b i ) (ai,bi) (ai,bi) a , b a,b ab都会不相同,那我们就至少保证选出的 3 3 3 ( a i , b i ) (ai,bi) (ai,bi)中有两个 a a a是相同的,两个 b b b是相同的。
在这里插入图片描述
我们每一次都枚举 b b b的数值,那么当前 b b b不满足条件的总数就为:
(和 b b b相同个数的 − 1 -1 1)* ∑ \sum (与 b b b对着的所有 a a a的个数 − 1 -1 1)。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        ll n;ll a,b;
        cin>>n;
        map<ll,ll> mpa,mpb;
        map<ll,vector<ll> > mp;
        ///n*(n-1)*(n-2)/6
        ll sum=n*(n-1)*(n-2)/6;
        for(int i=1;i<=n;i++){
            cin>>a>>b;
            mpa[a]++;
            mpb[b]++;
            mp[b].push_back(a);
        }

        for(map<ll,ll>::iterator it=mpb.begin();it!=mpb.end();it++){
            ll tmp=0;
            for(int i=0;i<mp[it->first].size();i++){
                tmp+=(it->second-1)*(mpa[mp[it->first][i]]-1);
            }
            sum-=tmp;
        }
        cout<<sum<<endl;

    }
}

感谢阅读,希望能对你产生一点用处。

权游第8季第2季册封骑士

"In the name of the Warrior,I charge you to be brave."
"In the name of the Father,I charge you to be just."
"In the name of the Mother,I charge you to be defend in innocent."
"Arise,Brienne of Tarth,a knight of the Seven Kingdoms."

吾日三省吾身:日更否?刷题否?快乐否?
更新了,但不是日更;已刷;happy!
吾心满意足。

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值