Educational Codeforces Round 115 (Rated for Div. 2)

本文介绍了参加EducationalCodeforcesRound115编程竞赛的经历,分享了A、B、C、D四道题目的解题思路和代码实现,涉及矩阵遍历、数组划分、平均数计算和序列匹配等算法。在解决数组问题时,强调了正确理解和巧妙运用数据结构及算法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Educational Codeforces Round 115 (Rated for Div. 2)


又是脑瘫的一天,C题想着用商和余数来表示平均数(人太傻了,没办法),还等到WA了一发才发现这是个错误的想法,还是老老实实的用double吧!D一个long long int 没开连WA两发,真实傻到了家。咕咕咕,还是咕出一篇题解来吧!


A - Computer Game


题意:

Monocarp在玩一个游戏,他现在处在一个 2 × n 2\times n 2×n的a矩阵内,如果 a [ i ] [ j ] = 1 a[i][j]=1 a[i][j]=1则说明该位置不能行走,他当前在(1,1)这个位置,问他是否能走到(2,n)这个位置上。每一次行走只能往周围8个方向。


思路:

只需要判断是否存在 a [ 1 ] [ j ] = a [ 2 ] [ j ] = 1 a[1][j]=a[2][j]=1 a[1][j]=a[2][j]=1,如果存在的话则说明从j的左边是无法到达右边的,则一定也不能到达(2,n)


参考代码:
#include<bits/stdc++.h>
using namespace std;
char a[3][110];
int n;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=2;i++)
        scanf("%s",a[i]+1);
        if(a[1][1]=='1'||a[2][n]=='1')printf("NO\n");
        else
        {
            int flag=0;
            for(int i=1;i<=n;i++)
            {
                if(a[1][i]=='1'&&a[2][i]=='1')
                {
                    flag=1;
                    break;
                }
            }
            if(flag==0)printf("YES\n");
            else printf("NO\n");
        }
    }
   // system("pause");
    return 0;
}


B - Groups


题意:

一个班有n个人,每一个都对自己的周一到周五都有计划(0代表空闲,1代表忙碌),现在要组织两个活动需要全班人的参与且两个活动不能在同一天,班长计划把班级里的人分成两组(一个人不能同时参加两组),问是否能将班级里的同学根据空闲情况分成两组参加活动。


思路:

以为只有5天,所以可以枚举组织活动的两天进行check即可。


参考代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int a[maxn][8],n;
bool check(int x,int y)
{
    int sum=0,sumx=0,sumy=0;
    for(int i=1;i<=n;i++)
    {
        int xx=a[i][x],yy=a[i][y];
        if(xx==1&&yy==1)sum++;
        else if(xx==1)sumx++;
        else if(yy==1)sumy++;
    }
    int minn=min(sumx,sumy),maxx=max(sumx,sumy);
    if(sum<maxx-minn)return false;
    else 
    {
        sum-=maxx-minn;
        if(sum%2==0)
        {
            if(2*(maxx+sum/2)==n)return true;
            else return false;
        }
        else return false;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=5;j++)
            scanf("%d",&a[i][j]);
        }
        int flag=0;
        for(int i=1;i<=5;i++)
        {
            for(int j=1;j<=5;j++)
            {
                if(i==j)continue;
                if(check(i,j)==true)
                {
                   // cout<<i<<" "<<j<<endl;
                    flag=1;
                    break;
                }
            }
            if(flag==1)break;
        }
        if(flag==1)printf("YES\n");
        else printf("NO\n");
    }
  //  system("pause");
    return 0;
}


C - Delete Two Elements


题意:

给定一个长度为n的a数组,求出它的平均数k,问存在多少个二元组 ( i , j ) 且 i < j (i,j)且i<j (i,j)i<j使得删去 a [ i ] 和 a [ j ] a[i]和a[j] a[i]a[j]后剩下的n-2个数的平均数还是k


思路:

删除两个数后使得剩下的数的平均值仍为k,则删除的两个数的平均值应该为k。假如删去的一个数为x,则另一个不就是 2 × k − x 2\times k-x 2×kx嘛,则可以记录每一个数的数量,然后枚举x,计算每一个x对答案的贡献求和即可。


参考代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PDD pair<double,double>
const int maxn=2e5+10;
double a[maxn];
int n;
unordered_map<double,ll>mm;
map<PDD,bool>vis;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        mm.clear();
        vis.clear();
        scanf("%d",&n);
        double sum=0;
        vector<double>v;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf",&a[i]);
            v.push_back(a[i]);
            sum+=a[i];
            mm[a[i]]++;
        }
        double k=sum/n;
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        ll ans=0;
        for(int i=0;i<v.size();i++)
        {
            double xx=2*k;
            if(mm[xx-v[i]]>0&&vis[{v[i],xx-v[i]}]==false&&vis[{xx-v[i],v[i]}]==false)
            {
                if(v[i]!=xx-v[i])ans+=mm[v[i]]*mm[xx-v[i]];
                else 
                {
                    ll val=mm[v[i]]-1;
                    ans+=val*(val+1)/2;
                }
                vis[{v[i],xx-v[i]}]=true;
                vis[{xx-v[i],v[i]}]=true;
            }
        }
        printf("%lld\n",ans);
    }
   // system("pause");
    return 0;
}


D - Training Session


题意:

给定两个长度为n的a、b数组,并且对于任意一对 ( i , j ) 不 存 在 a [ i ] = a [ j ] 并 且 b [ i ] = b [ j ] (i,j)不存在a[i]=a[j]并且b[i]=b[j] (i,j)a[i]=a[j]b[i]=b[j],求任选互不相等的(i,j,k)至少满足以下两个条件中一个的三元组个数:

1. a [ i ] 、 a [ j ] 、 a [ k ] 互 不 相 等 a[i]、a[j]、a[k]互不相等 a[i]a[j]a[k]

2. b [ i ] 、 b [ j ] 、 b [ k ] 互 不 相 等 b[i]、b[j]、b[k]互不相等 b[i]b[j]b[k]


思路:

如果直接求满足条件的方案数是很难求得出来的,所以我们可以求出所有的方案数-不符合要求的方案数。

由题可知,不满足条件的三元组一定是以下形式:

a [ i ] = a [ j ] 且 b [ i ] ! = b [ j ] a[i]=a[j]且b[i]!=b[j] a[i]=a[j]b[i]!=b[j]

a [ k ] ≠ a [ i ] 且 ( b [ k ] = b [ i ] 或 b [ k ] = b [ j ] ) a[k]\ne a[i]且(b[k]=b[i]或b[k]=b[j]) a[k]=a[i]b[k]=b[i]b[k]=b[j]


这样的话我们可以for循环枚举 a [ i ] 、 b [ i ] a[i]、b[i] a[i]b[i],然后在第一个数等于a[i]的里面找到 a [ j ] 和 b [ j ] a[j]和b[j] a[j]b[j],那最后k的所有取值数只能是 b [ k ] = b [ i ] 或 b [ k ] = b [ j ] b[k]=b[i]或b[k]=b[j] b[k]=b[i]b[k]=b[j]的数量。

假设:

a1=2,b1=4

a2=2,b2=1

a3=2,b3=2

则对于i=1,j=2时b[k]的取值只能是4 和1,所以只需要求出a不等于2且b=4或1的序列的数量则为三元组的贡献。


参考代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int,int>
const int maxn=2e5+10;
unordered_map<int,ll>m1;
unordered_map<int,vector<int>>mp;
ll vis[maxn],n;
PII p[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        m1.clear();
        mp.clear();
        for(int i=1;i<=n;i++)
        {
            int l,r;
            vis[i]=-1;
            scanf("%d%d",&l,&r);
            p[i]={l,r};
            m1[r]++;
            mp[l].push_back(r);
        }
        ll ans=n*(n-1)*(n-2)/6;
        ll sum=0;
        for(int i=1;i<=n;i++)
        {
            int xx,yy;
            xx=p[i].first,yy=p[i].second;
            if(vis[xx]==-1)
            {
                ll sum1=0;
                for(auto it:mp[xx])
                sum1+=m1[it]-1;
                vis[xx]=sum1;
            }
            ll hh=m1[yy]-1;
            sum+=hh*(mp[xx].size()-1)+vis[xx]-hh;
        }
        printf("%lld\n",ans-sum/2);
    }
   // system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值