Educational Codeforces Round 98 (Rated for Div. 2) 解题报告(A.思维 B.二分 C.栈+思维 D.找规律 E.预处理)

官方题解:https://codeforces.com/blog/entry/84847

A - Robot Program

要到达终点的最短路径,一定是要么不用West,要么不用North,并且,其指令序列一定为E x E x E x……x E或者S x S x S x……x S交错排成,因此,我们可以得到结论答案为max(x,y)*2,并且当x==y的时候,S(E)与x数量相同,需要+1。

t=input()
t=int(t)
while t>0:
    t-=1
    x,y=input().split()
    x=int(x)
    y=int(y)
    ans=max(x,y)*2
    if(x!=y):ans-=1
    print(ans)

B - Toy Blocks

由于拿了第i个箱子之后,都是剩下n-1个箱子,并且,因为第i个箱子的物品被分给其他箱子,所以总数一直为sum,并且平均分后每个箱子为sum/(n-1)个物品,因此,我们可以二分平均分后的物品为ans,则,ans满足:ans>=max(a[i])并且(n-1)*ans>=sum。注意r需要开到2e9。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++i)
#define per(i,a,b) for(int (i)=(b);(i)>=(a);--i)
template<typename T>
void read(T&x){
    x=0;
    ll f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f*=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        x=x*10+ch-'0';
        ch=getchar();
    }
}
template<typename T>
void write(T x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
//===============================================
#define int ll
const int maxn=1e5+100;
int t,n;
ll a[maxn];
ll sum=0,mx;
bool check(ll x){
    return (n-1)*x>=sum&&x>=mx;
}
int solve(){
    sum=0,mx=0;
    rep(i,1,n){
        sum+=a[i];
        mx=max(mx,a[i]);
    }
    ll l=mx,r=2e9+100;
    while(l<=r){
        ll m=(l+r)>>1;
        if(check(m)){
            r=m-1;
        }
        else{
            l=m+1;
        }
    }
    return (n-1)*(r+1)-sum;
}

signed main(){
    read(t);
    while(t--){
        read(n);
        rep(i,1,n)read(a[i]);
        write(solve());putchar('\n');
    }
    return 0;
}

C - Two Brackets

这题会联想到数据结构课上讲的栈和括号序列的应用,并且由于这题不需要连续的,因此,我们可以对这个算法进行变形:当遇到左括号时,将他压入栈中。当遇到右括号时候,若此时栈中有左括号,则pop一个,统计答案。否则,我们直接忽略他(因为此时左边无剩余的左括号,无法搭配删除)。返回统计答案即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++i)
#define per(i,a,b) for(int (i)=(b);(i)>=(a);--i)
template<typename T>
void read(T&x){
    x=0;
    ll f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f*=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        x=x*10+ch-'0';
        ch=getchar();
    }
}
template<typename T>
void write(T x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
//===============================================
#define int ll
const int maxn=2e5+100;
int t;
char str[maxn];
ll solve(){
    int len=strlen(str+1);
    int pos1,pos2;
    pos1=pos2=0;
    int ans=0;
    rep(i,1,len){
        if(str[i]=='[')pos1++;
        if(str[i]=='(')pos2++;
        if(str[i]==']'){
            if(pos1)pos1--,ans++;
        }
        if(str[i]==')'){
            if(pos2)pos2--,ans++;
        }
    }
    return ans;
}

signed main(){
    //freopen("in.txt","r",stdin);
    read(t);
    while(t--){
        scanf("%s",str+1);
        write(solve());putchar('\n');
    }
    return 0;
}

D - Radio Towers

听轩哥的就对了:https://blog.csdn.net/weixin_46163391/article/details/109877652

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++i)
#define per(i,a,b) for(int (i)=(b);(i)>=(a);--i)
template<typename T>
void read(T&x){
    x=0;
    ll f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f*=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        x=x*10+ch-'0';
        ch=getchar();
    }
}
template<typename T>
void write(T x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
//===============================================
const int maxn=2e5+100;
ll mod=998244353;
ll ksm(ll a,ll n){
    ll res=1;
    while(n){
        if(n&1) res=res*a%mod;
        a=a*a%mod;
        n>>=1;
    }
    return res;
}

ll n;
ll f[maxn];
ll solve(){
    ll fm=ksm(ksm(2,n),mod-2)%mod;
    f[1]=1;
    f[2]=1;
    rep(i,3,n){
        f[i]=(f[i-1]+f[i-2])%mod;
    }
    return f[n]*fm%mod;
}

int main(){
    //freopen("in.txt","r",stdin);
    read(n);
    write(solve());
    return 0;
}

E - Two Editorials

暴力的方法是:枚举两个出题人的起点,之后枚举任务,统计贡献,复杂度O(mn^2)
考虑优化统计第二个出题人的贡献:如果能够在枚举统计第一个出题人贡献的时候,O(1)查询此时第二个出题人的贡献,则复杂度能够降到O(nm)。
考虑开数组计下第二个出题人的贡献。不妨设第一个出题人选的区间在前,第二个出题人选的区间在后。
此时,我们需要先定义“前”和“后”:我们选择根据区间的中点位置的前后定义前后,原因如下:
设出题人选择的区间为S,目前一个题目的区间为T,通过观察,我们可以知道:两个区间中点越靠近,则相交区域越大(不一定是严格增大)。因此,我们可以通过中点定义区间前后。
我们根据前后顺序对m个区间sort一次。
之后,我们计算第二个出题人的贡献。数组val[i]表示第二个出题人从i~m个区间(后缀)内选择,最大的贡献。之后,我们还是要枚举第二个出题人的起点,去更新val[i]。
之后,我们枚举第一个出题人的起点,从前向后枚举每个问题区间(前缀),计算从1~j范围内第一个出题人的贡献,再加上刚才计算的j+1~m区间内第二个出题人的贡献,就是两人的总贡献。
这里有个疑问:题目里,教练只会选择能给他们尽量多的出题人去听,而我们的模拟过程并没有看到和这个相关的部分。
我的理解是:我们枚举第一个出题人的起点计算贡献时,是计算了1~i的贡献,然后,数组里记下了是i+1~m的贡献,若区间i+1与第一个出题人的交集更大,那等会枚举到i+1任务的时候这个方案是更优的,所以,不会对最后结果产生影响,因此,这个算法是正确的。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);++i)
#define per(i,a,b) for(int (i)=(b);(i)>=(a);--i)
template<typename T>
void read(T&x){
    x=0;
    ll f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f*=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        x=x*10+ch-'0';
        ch=getchar();
    }
    x*=f;
}
template<typename T>
void write(T x){
    if(x<0)x=-x,putchar('-');
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
//=====================================================
#define int ll
const int maxn=2e3+100;
struct node{
    int l,r;
}da[maxn];
int val[maxn];
int n,m,k;
int solve(){
    sort(da+1,da+1+m,[](const node&a,const node&b){
        return a.l+a.r<b.l+b.r;
    });
    rep(l,1,n-k+1){
        int r=l+k-1;
        int pos=0;
        per(j,1,m){
            pos+=(max(min(da[j].r,r)-max(da[j].l,l)+1,0ll));
            val[j]=max(val[j],pos);
        }
    }
    int res=0;
    rep(l,1,n-k+1){
        int r=l+k-1;
        int pos=0;
        rep(j,1,m){
            pos+=max(min(da[j].r,r)-max(da[j].l,l)+1,0ll);
            res=max(res,pos+val[j+1]);
        }
    }
    return res;
}
signed main(){
    //freopen("in.txt","r",stdin);
    read(n),read(m),read(k);
    rep(i,1,m){
        read(da[i].l),read(da[i].r);
    }
    write(solve());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值