CSP-J 复赛模拟 第三轮 赛后补题报告

日期:2023 年 10 月 2 日 学号:S08503 姓名:徐浩轩

比赛概况: 比赛总分共 4 题,满分 400,赛时拿到 70 分,其中第一题 40 分,第二题 30 分,第三题 0 分,第四题 0 分。

比赛过程: 先用模拟写了A题40分,B题根据部分样例骗了30分,CD题偷分失败,未得分。

题解报告: 
(1) 第一题:答案错误:赛中 40 分,已补题 
题意:给定A数组,求满足条件的B数组最小字典序是多少 赛时本题做题想法:模拟
AC 代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[100005];
map<int,int> vis;
map<int,int> num;
int main(){
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>a[i];
        vis[a[i]]=1;
    }
    int cnt=1;
    for(int i=1;i<=n;++i){
        if(num.count(a[i])==0){
            while(vis.count(cnt)){
                cnt++;
            }
            vis[cnt]=1;
            num[a[i]]=cnt;
        }
    }
    for(int i=1;i<=n;++i){
        cout<<num[a[i]]<<" ";
    }
    return 0;
}

(2) 第二题:答案错误 :赛中 70 分,已补题 
题意:给定5个整数n,m,p,t,k,求最大的知识能量。
赛时本题做题想法:模拟
 AC 代码:
#include<bits/stdc++.h>
using namespace std;
long long n,m,k,q,t,sum=0;
int main(){
    cin>>n>>m>>k>>q>>t;
    if(m<k){
        cout<<"0";
        return 0;
    }
    if(n>m/k){
        n=m/k;
    }
    long long l=m%n;
    long long ans1=l*min((m/n+1)*t,q);
    long long ans2=(n-l)*min((m/n)*t,q);
    cout<<ans1+ans2;
    return 0;
}


(3) 第三题:答案错误:赛中 50 分,已补题 
题解:区间最大值和最小值的绝对值相等,有以下两种情况:
    1.区间中只有同一种数字。这个比较简单,通过简单的 for 循环向后计数得到。
    2.区间中最大值和最小值为相反数。
         第二种情况具体来说,就是最大值 ,最小值 ,和最大值 ,最小值 。
         考虑如何求解第二种情况。
         考虑固定左端点时,如何找合法的右端点:
    1.对于最大值为1最小值-1的情况:右端点需要保证:区间有1和-1,区间中没有2和-2.
       这可以通过维护左端点向后的1/-1/2/-2的初始位置找到。右端点的起始位置为max
       (下一个1的位置,下一个-1的位置),结束位置为 min (下一个 的位置,下一个 的位置)
    2.对于最大值为 最小值 的情况:右端点需要保证:区间中有 和 。维护方法类似上面。
         至此本题做完,复杂度为 O(n)

AC 代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+5;
const int inf=0x3f3f3f3f;
ll n,ans,num[N];
int nxt[N][5];
int startpos,endpos;
int main(){
    cin>>n;
    memset(nxt,0x3f,sizeof(nxt));
    for(int i=1;i<=n;++i){
        cin>>num[i];
    }
    ll ret=1,lst=num[1];
    for(int i=2;i<=n;++i){
        if(num[i]==lst){
            ++ret;
        }
        else{
            ans+=ret*(ret+1)/2;
            ret=1;
            lst=num[i];
        }
    }
    ans+=ret*(ret+1)/2;
    for(int i=n;i>=1;--i){
        for(int j=0;j<=4;++j){
            nxt[i][j]=nxt[i+1][j];
        }
        nxt[i][num[i]+2]=i;
        int maxpos1=nxt[i][1+2],maxpos2=nxt[i][2+2];
        int minpos1=nxt[i][-1+2],minpos2=nxt[i][-2+2];
        startpos=max(maxpos2,minpos2);
        endpos=n+1;
        if(startpos!=inf&&startpos<endpos){
            ans+=endpos-startpos;
        }
        startpos=max(maxpos1,minpos1);
        endpos=min(min(maxpos2,minpos2),(int)n+1);
        if(startpos!=inf&&startpos<endpos){
            ans+=endpos-startpos;
        }
    }
    cout<<ans;
    return 0;
}

(4) 第四题:答案错误:赛中 0 分,已补题
 题解:30%数据下:可以直接暴力枚举每个点作为根的情况,然后dfs出每个点到根的距离,计算方差。
           另外的20%数据下:为一条链表的情况,那么根设置在中间的位置是优的。

 AC 代码:
#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int maxn=1e5+10;
ll sum2[maxn],sum1[maxn],sz[maxn],n,res;
vector<int> g[maxn];
void dfs1(int u,int fa){
    for(int i=0;i<g[u].size();++i){
        int v=g[u][i];
        if(v==fa){
            continue;
        }
        dfs1(v,u);
        sz[u]+=sz[v];
        sum1[u]+=sum1[v];
        sum2[u]+=sum2[v];
    }
    sum2[u]+=sz[u]+2*sum1[u];
    sum1[u]+=sz[u];
    sz[u]++;
    return ;
}
void dfs2(int u,int f,ll s1,ll s2){
    res=min(res,n*(s2+sum2[u])-(sum1[u]+s1)*(sum1[u]+s1));
    for (int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==f){
            continue;
        }
        ll ret1=sum1[u]-(sum1[v]+sz[v])+s1;
        ll ret2=sum2[u]-(sum2[v]+2*sum1[v]+sz[v])+s2;
        ll szu=n-sz[v];
        dfs2(v,u,ret1+szu,ret2+2*ret1+szu);
    }
    return;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;++i){
            g[i].clear();
            sum1[i]=sum2[i]=sz[i]=0;
        }
        for(int i=1;i<=n-1;++i){
            int u,v;
            cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        res=LONG_LONG_MAX;
        dfs1(1,0);
        dfs2(1,0,0,0);
        cout<<res<<"\n";
    }
    return 0;
}

赛后总结: 本次比赛出现了题目名写错丢分的问题,以后需要注意题目名,以防不必要的丢分。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
CSP-J复赛历年试pdf是指CSP-J复赛历年试的PDF文件。CSP-J是中国计算机学会(CCF)主办的一项高中生计算机科学与编程的竞赛。复赛CSP-J竞赛的第二个阶段,参赛者需要通过初赛选拔才能进入复赛CSP-J复赛历年试pdf中包含了以往CSP-J复赛的试和答案。这些试主要涵盖了计算机科学与编程的各个方面,包括编程语言、算法、数据结构、计算机网络等。参赛者可以通过研究历年试,了解CSP-J竞赛的型和出风格,提高自己的解能力和编程水平。 CSP-J复赛历年试pdf对于参赛者来说具有很大的参考价值。通过研究这些试,参赛者可以了解到高水平的计算机科学与编程问是如何被设计和解决的。同时,参赛者还可以通过尝试解答这些试,检验自己的知识和技能,发现自己的不足之处并进行改进。 此外,CSP-J复赛历年试pdf还对教师和学生进行教学和学习有很大的帮助。教师可以利用这些试作为教学资源,丰富教学内容和方法,提高学生的计算机科学与编程能力。学生可以通过研究这些试,扩展知识面,提升解决问和编程的能力。 总之,CSP-J复赛历年试pdf是一份重要的学习和竞赛资料,对参赛者、教师和学生都具有很大的参考和帮助作用。通过研究这些试,大家可以更好地了解计算机科学与编程的相关知识和技能,并提升自己的竞赛和学习能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值