Educational Codeforces Round 24 题解

本文提供了CodeForces平台上多个算法题目的详细解答,包括数学问题、模拟游戏过程、处理复杂的数据结构等,涉及线段树、二分搜索等高级算法。

题目链接:http://codeforces.com/contest/818/problem/A

A:数学,水题。

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

int main()
{
    LL n, k;
    scanf("%lld%lld",&n,&k);
    LL x = n/(2*(k+1));
    if(x == 0){
        printf("0 0 %lld\n", n);
    }
    else{
        printf("%lld %lld %lld\n", x, k*x, n-(k+1)*x);
    }
}

B,水题,模拟。题意:给出一个排列a1…an,进行m轮游戏,首先选定一个leader作为l[1],l[i+1]=a[l[i]]+l[i] a[l[i]]+l[i]=l[i+1] 所以 a[l[i]]=l[i+1]-l[i] 如果遇到有冲突的情况特判一下输出-1(一个以上的位置是同一个数或同一个位置几次得到的结果不一样)

#include <bits/stdc++.h>
using namespace std;
int n, m, l[110], a[110], ans[110], temp[110];
int vis[110];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++) scanf("%d",&l[i]);
    bool flag = 0;
    for(int i=1; i<=n; i++){
        int st = l[1];
        memset(vis, 0, sizeof(vis));
        memset(temp, 0, sizeof(temp));
        int pos = 1;
        temp[1] = i;
        vis[i] = 1;
        bool ok = 1;
        for(int j=2; j<=m; j++){
            if(temp[st]==0){
                int x = l[j]-l[j-1];
                if(x<=0) x+=n;
                if(x>n) x-=n;
                temp[st]=x;
                ++vis[x];
                st = l[j];
            }
            else{
                int x = temp[st]+st;
                if(x>n) x-=n;
                if(x==l[j]){
                    st = l[j];
                }
                else{
                    ok = 0;
                }
            }
        }
        for(int j=1; j<=n; j++){
            if(vis[j]>1){
                ok = 0;
                break;
            }
        }
        if(ok){
            for(int j=1; j<=n; j++){
                if(temp[j]) ans[j] = temp[j];
                else{
                    for(int k=1; k<=n; k++){
                        if(!vis[k]){
                            ans[j] = k;
                            vis[k] = 1;
                            break;
                        }
                    }
                }
            }
            flag = 1;
            break;
        }
    }
    if(flag==0){
        puts("-1");
    }
    else{
        for(int i=1; i<=n; i++) printf("%d ", ans[i]);
        printf("\n");
    }
    return 0;
}

C:有d个沙发,每个沙发占据相邻两个格子,定义一个沙发A在另一个沙发B左边为:存在沙发A的格子a和沙发B的格子b使得xa小于xb,求出一个沙发满足给出的cntl,cntr,cntt,cntb m和n都不超过1e5,直接处理出前缀和,O(n)可求

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
struct node{
    int x1,y1,x2,y2;
}sofa[maxn];
int d, n, m, cntl, cntr, cntt, cntb, ans, sum1[maxn], sum2[maxn], sum3[maxn], sum4[maxn];

int main(){

    scanf("%d%d%d", &d,&n,&m);
    for(int i=1; i<=d; i++){
        scanf("%d%d%d%d", &sofa[i].x1,&sofa[i].y1,&sofa[i].x2,&sofa[i].y2);
        sum1[min(sofa[i].x1,sofa[i].x2)]++;
        sum2[max(sofa[i].x1,sofa[i].x2)]++;
        sum3[min(sofa[i].y1,sofa[i].y2)]++;
        sum4[max(sofa[i].y1,sofa[i].y2)]++;
    }
    scanf("%d%d%d%d", &cntl,&cntr,&cntt,&cntb);
    for(int i=1; i<=n; i++) sum1[i]+=sum1[i-1];
    for(int i=n; i>=1; i--) sum2[i]+=sum2[i+1];
    for(int i=1; i<=m; i++) sum3[i]+=sum3[i-1];
    for(int i=m; i>=1; i--) sum4[i]+=sum4[i+1];
    ans = -1;
    for(int i=1; i<=d; i++){
        int l = sum1[max(sofa[i].x1, sofa[i].x2)-1];
        int r = sum2[min(sofa[i].x1, sofa[i].x2)+1];
        if(sofa[i].x1 != sofa[i].x2) l--, r--;
        int t = sum3[max(sofa[i].y1, sofa[i].y2)-1];
        int b = sum4[min(sofa[i].y1, sofa[i].y2)+1];
        if(sofa[i].y1 != sofa[i].y2) t--,b--;
        if(l == cntl && r == cntr && t == cntt && b == cntb){
            ans = i;
            break;
        }
    }
    printf("%d\n", ans);
    return 0;
}

D,有n辆车依次驶过,给定对方选择的一个颜色a,请你选择一个颜色b使得在任一时刻cntb>=cnta。

解法:这道题本来O(n)扫一遍就好了,傻逼强行怼了线段树。我的做法就是对所有的颜色开一个线段树,当颜色等于A的时候所有颜色的值-1,不等于A的时候,如果当前颜色所在位置的值>=0的话,给当前值+1,最后查找这个线段树有没有>=0的节点,有的话输出这个值就好了。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
int n, A, c[maxn];
struct node{
    int l,r,len,sum;
    int lazy;
}tree[maxn*4];
void pushup(int rt){
    tree[rt].sum = tree[rt*2].sum+tree[rt*2+1].sum;
}
void pushdown(int rt){
    if(tree[rt].lazy){
        tree[rt*2].lazy+=tree[rt].lazy;
        tree[rt*2+1].lazy+=tree[rt].lazy;
        tree[rt*2].sum += tree[rt*2].len*tree[rt].lazy;
        tree[rt*2+1].sum += tree[rt*2+1].len*tree[rt].lazy;
        tree[rt].lazy = 0;
    }
}
void Build(int l, int r, int rt){
    tree[rt].l = l, tree[rt].r = r, tree[rt].sum = 0, tree[rt].lazy = 0, tree[rt].len = r-l+1;
    if(l == r){
        return;
    }
    int mid = (l+r)/2;
    Build(l,mid,rt*2);
    Build(mid+1,r,rt*2+1);
    pushup(rt);
}
void update(int L, int R, int c, int rt){
    if(L<=tree[rt].l&&tree[rt].r<=R){
        tree[rt].sum += c*(tree[rt].len);
        tree[rt].lazy += c;
        return;
    }
    pushdown(rt);
    int mid = (tree[rt].l+tree[rt].r)/2;
    if(R<=mid) update(L,R,c,rt*2);
    else if(L>mid) update(L,R,c,rt*2+1);
    else{
        update(L,mid,c,rt*2);
        update(mid+1,R,c,rt*2+1);
    }
    pushup(rt);
}
int query(int L, int R, int rt){
    if(L<=tree[rt].l&&tree[rt].r<=R){
        return tree[rt].sum;
    }
    pushdown(rt);
    int mid = (tree[rt].l+tree[rt].r)/2;
    if(R<=mid) return query(L,R,rt*2);
    else if(L>mid) return query(L,R,rt*2+1);
    else return query(L,mid,rt*2)+query(mid+1,R,rt*2+1);
}

int main()
{
    scanf("%d%d",&n,&A);
    for(int i=1; i<=n; i++) scanf("%d", &c[i]);
    Build(1,1000000,1);
    int ans = -1;
    for(int i=1; i<=n; i++){
        if(c[i]==A){
            update(1,1000000,-1,1);
        }
        else{
            if(query(c[i],c[i],1)>=0){
                update(c[i],c[i],1,1);
            }
        }
    }
    for(int i=1; i<=1000000; i++){
        if(i==A) continue;
        if(query(i,i,1)>=0){
            ans = i;
            break;
        }
    }
    printf("%d\n", ans);
    return 0;
}

E,有多少连续的ai…aj的乘积是k的倍数
解法:将k分解质因数,处理出序列每个质因数个数的前缀和,对于每个左端点通过二分来得到最小的能使乘积为k的倍数的右端点

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 400010;
LL n, k;
LL a[maxn];
LL num1[20], num2[20], cnt=0;
LL sum[maxn][20];
bool check(LL x, LL y){
    for(int i=0; i<cnt; i++){
        LL temp = sum[y][i]-sum[x-1][i];
        if(temp<num2[i]) return false;
    }
    return true;
}
int main()
{
    scanf("%lld%lld", &n,&k);
    LL x = k;
    for(LL i=2; i*i<=x; i++){
        if(x%i==0){
            int p = 0;
            num1[cnt++] = i;
            while(x%i==0){
                x/=i;
                p++;
            }
            num2[cnt-1] = p;
        }
    }
    if(x > 1){
        num1[cnt++] = x;
        num2[cnt-1] = 1;
    }
    memset(sum, 0, sizeof(sum));
    for(LL i=1; i<=n; i++){
        scanf("%lld", &a[i]);
        for(int k = 0; k < cnt; k++){
            sum[i][k] = sum[i-1][k];
            while(a[i]%num1[k]==0){
                sum[i][k]++;
                a[i]/=num1[k];
            }
        }
    }
    LL anss = 0;
    for(LL i=1; i<=n; i++){
        LL l = i, r = n, ans = n;
        while(l<=r){
            LL mid = (l+r)/2;
            if(check(i, mid)) ans = mid, r=mid-1;
            else l = mid+1;
        }
        if(check(i, ans)) anss = anss+n-ans+1;
    }
    printf("%lld\n", anss);
    return 0;
}

F,n个点的图,桥的个数要求不小于边数的一半,问边数的最大值
解法:n个点中k个点两两相连有k*(k-1)/2条边,其余的点顺次相连为桥n-k条边,当k*(k-1)/2<=n-k时才符合要求 可以发现f(k)=n-k+min(n-k,k*(k-1)/2)是一个单峰函数,于是三分得到答案

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int q;
LL n, ans;
LL check(LL mid){
    return n-mid+min(n-mid,(mid-1)*mid/2);
}
int main(){
    scanf("%d", &q);
    while(q--){
        scanf("%lld", &n);
        LL l = 1, r = n;
        while(l + 1 < r){
            LL mid = (l+r)/2;
            LL midd = (mid+r)/2;
            if(check(mid)<check(midd)) l = mid;
            else r = midd;
        }
        printf("%lld\n", max(check(l),check(l+1)));
    }
}

G,没读

源码地址: https://pan.quark.cn/s/a4b39357ea24 欧姆龙触摸屏编程软件MPTST 5.02是专门为欧姆龙品牌的工业触摸屏而研发的编程解决方案,它赋予用户在直观界面上构建、修改以及排错触摸屏应用程序的能力。 该软件在工业自动化领域具有不可替代的地位,特别是在生产线监视、设备操控以及人机互动系统中发挥着核心作用。 欧姆龙MPTST(Machine Process Terminal Software Touch)5.02版本配备了多样化的功能,旨在应对不同种类的触摸屏项目要求。 以下列举了若干核心特性:1. **图形化编程**:MPTST 5.02采用图形化的编程模式,允许用户借助拖拽动作来设计屏幕布局,设定按钮、滑块、指示灯等组件,显著简化了编程流程,并提升了工作效率。 2. **兼容性**:该软件能够适配欧姆龙的多个触摸屏产品线,包括CX-One、NS系列、NJ/NX系列等,使用户可以在同一个平台上完成对不同硬件的编程任务。 3. **数据通信**:MPTST 5.02具备与PLC(可编程逻辑控制器)进行数据交互的能力,通过将触摸屏作为操作界面,实现生产数据的显示与输入,以及设备状态的监控。 4. **报警与事件管理**:软件中集成了报警和事件管理机制,可以设定多种报警标准,一旦达到预设条件,触摸屏便会展示对应的报警提示,助力操作人员迅速做出响应。 5. **模拟测试**:在设备实际连接之前,MPTST 5.02支持用户进行脱机模拟测试,以此验证程序的正确性与稳定性。 6. **项目备份与恢复**:为了防止数据遗失,MPTST 5.02提供了项目文件的备份及还原功能,对于多版本控制与团队协作具有显著价值。 7. **多语言支持**:针对全球化的应...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值