Educational Codeforces Round 143

A

题意

两根红蓝方块组成的柱子,可以任意将一根柱子顶端的一个方块移动到另一根柱子顶端,问是否能使得两根柱子均为红蓝交错的颜色。

思路

显然可以转化成一个序列能否从中间分割成两个红蓝交错的序列,也就是判断是否有三个连续的颜色,或者两个颜色连续出现两次以上。

代码

#include<bits/stdc++.h>
 
using namespace std;
 
const int MAX=1e3;
 
char s1[MAX],s2[MAX];
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        scanf("%s%s",s1,s2);
        for(int i=m-1,j=n;i>=0;i--,j++)
            s1[j]=s2[i];
        n+=m;
        int len=1,cnt=0;
        for(int i=1;i<n;i++)
        {
            if(s1[i]==s1[i-1])len++;
            else len=1;
            if(len>2)break;
            if(len==2)cnt++;
        }
        if(len>2||cnt>1)printf("NO\n");
        else printf("YES\n");
    }
}

B

题意

给一个数轴,然后有若干闭区间,求能否任意移除若干区间,使得覆盖到k点的区间个数 严格大于 覆盖到其他任何一点的区间个数。

思路

可以巧妙思考一下,实际上只有k点恰好同时是一个区间的左端点和一个区间的右端点(可以是同一个左右相等的区间),当且仅当在这种状态下,k能达成题目要求。

证明如下:

充分性容易想到。

使用反证法证明其必要性。

设节点分数为覆盖节点的区间个数,假设k达成题目要求,但不是上述种类的节点,那么有三种情况。

  • 如果k没有被任何区间覆盖,那么分数为0,不可能严格大于任何点的分数。
  • 如果k仅为某在其左侧区间的右端点,那么左侧任何能给k加分的区间,必定能给k-1点加分。同时,其右侧区间能给k加分的,也一定能给k-1加分(区间左端点会跨过k,至少落在k-1),那么k-1的分数一定大于等于k分数。
  • 同理可得如果k仅为某在其右侧区间的左端点,那么k+1的分数一定大于等于k分数。

因此可得矛盾,可以证明其必要性。

代码

#include<bits/stdc++.h>
 
using namespace std;
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,k,l,r;
        bool L=0,R=0;
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&l,&r);
            if(l==k)L=1;
            if(r==k)R=1;
        }
        if(L&&R)printf("YES\n");
        else printf("NO\n");
    }
}

C

题意

n杯茶,每杯ai单位,同时有n个品茶师,每次分别可以喝bi单位的茶。

开始时,茶和品茶师从1-n从左向右依次对应,然后每个人喝掉min(ai,bi)的茶,然后更新ai为被喝后剩余的数量。然后品茶师集体左移一格,i号到i-1号位,最左端的品茶师退出。逐次进行这一过程,直到最后一个品茶师退出。

求每个品茶师总共要和多少单位的茶。

思路

模拟一下可以发现,对于第i杯茶,要被i-n的品茶师喝,可以自然想到前缀数组。

b求前缀数组,然后可以遍历每一杯茶,二分查找最多可以被多少品茶师喝,然后用差分数组记录一下可供多少人喝,然后还剩下多少,最后统计答案。

代码

#include<bits/stdc++.h>
 
using namespace std;
using ll=long long;
 
const int MAX=2e5+5;
 
ll a[MAX],b[MAX],k[MAX],d[MAX],pre[MAX];
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            d[i]=0,k[i]=0;
        for(int i=0;i<n;i++)
            scanf("%I64d",&a[i]);
        for(int i=0;i<n;i++)
            scanf("%I64d",&b[i]);
        pre[0]=b[0];
        for(int i=1;i<n;i++)
            pre[i]=pre[i-1]+b[i];
        ll bias=0;
        for(int i=0;i<n;i++)
        {
            int pos=upper_bound(pre,pre+n,a[i]+bias)-pre;
            k[i]+=1;
            k[pos]-=1;
            d[pos]+=a[i]+bias-pre[pos-1];
            d[pos+1]-=a[i]+bias-pre[pos-1];
            bias=pre[i];
        }
        for(int i=1;i<n;i++)
            k[i]+=k[i-1],d[i]+=d[i-1];
        for(int i=0;i<n;i++)
        {
            b[i]=b[i]*k[i]+d[i];
            printf("%I64d ",b[i]);
        }
        printf("\n");
    }
}

D

题意

mm为偶数个三角形,每条边有权值,每个顶点可以被涂上红色或者蓝色,要求总体必须有相同数量的红色和蓝色。

一种涂色方案的分数为:顶点颜色不同的边的权值之和。

求有多少种方案能够最大化分数,最后取个模。

思路

很明显可以想到,一个三角形只有3R,3B,1R2B,2R1B四种涂色方案(旋转后的认为是一种),如果某个三角形选择3R,3B这种涂色方式,那么就对分数没有贡献,显然不可能使得分数最大化。那么要使得分数最大,就要选择1R2B,2R1B这种涂色方式,然后每个三角形选出最大的两条边,就可以使得分数最大化。

再考虑方案个数,由于有偶数个三角形,并且要求最终R,B数量想等,那么涂色方案应当是1R2B,2R1B各占一半。

再考虑每个三角形内部可能有相等的权值,衍生出不同的选择权值的方案,最后就变成了一个组合问题。

最终答案就是每个三角形内部的方案之积再乘以C^(m/2)_m种方案。

取模用逆元处理一下。

代码

#include<bits/stdc++.h>

using namespace std;
using ll=long long;

const int MOD=998244353;
const int MAX=3e5+5;

ll jc[MAX];

int qpow(int a,int k)
{
    int res=1;
    for(;k;k>>=1)
    {
        if(k&1)
            res=1ll*res*a%MOD;
        a=1ll*a*a%MOD;
    }
    return res%MOD;
}

int inv(int x){return qpow(x,MOD-2);}

int main()
{
    jc[0]=1;
    for(int i=1;i<=MAX;i++)
        jc[i]=jc[i-1]*i%MOD;
    int n,m,a,b,c;
    scanf("%d",&n);
    m=n/3;
    ll res=1;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        if(a<b)swap(a,b);
        if(a<c)swap(a,c);
        if(b<c)swap(b,c);
        if(a==b&&a==c)res*=3;
        else if(a==c||b==c)res*=2;
        res%=MOD;
    }
    res*=jc[n/3];
    res%=MOD;
    res*=inv(jc[n/3-n/6]);
    res%=MOD;
    res*=inv(jc[n/6]);
    res%=MOD;
    printf("%I64d\n",res);

}
posted @ 2023-03-02 16:51  cryingrain  阅读(24)  评论(0编辑  收藏  举报