CSP-J2023复赛题解

今年的csp-j难度对于我这种蒟蒻来讲看到的第一眼就是做不下去,今年的csp没有了水题,但其实认真分析也是能做出来的,话不多说,直接开始第一题《小苹果》

ok直接上代码,(自认为写的简单易懂)

#include<iostream>
using namespace std;
const int N=1e6+5;
int n,a[N],take,pos,ans,t_n;
int main()
{
	cin>>n;
	while(take<n)//没拿到n个就拿
	{
		ans++;
		for(int i=1;i<=n;i++){//第i个苹果,有: 
			if(a[i]==0){
				take++;
				if(i==n) t_n=ans;
				a[i]=1;//标记拿过了
				pos=i;
				break; 
			}
		}
		int cnt3=0;
		for(int i=pos+1;i<=n;i++){
			if(a[i]==0) cnt3++;
			if(cnt3==3){//要拿走 
			take++;
			if(i==n) t_n=ans;
			a[i]=1;
			cnt3=0;
			}
		}
	 } 
	cout<<ans<<" "<<t_n;
	return 0;
}

当我满怀信心的在洛谷上提交时:

却发现只有90分.......QAQ

然后马上发现了问题

#include<iostream>
using namespace std;
int n,flag,pick_end;
long long ans;
int main()
{
	cin>>n;
	while(n)//当还有苹果,就继续拿: 
	{
		//每次拿t个 
		ans++;
		int t=1+(n-1)/3;
		if((n-1)%3==0&&pick_end==0){
			pick_end=ans;
		}
		n-=t;
	}
	//无非是在草稿纸上多画几遍 
	cout<<ans<<' '<<pick_end;
	return 0;
}

AC

第二题难度陡然上升

继续上代码(我知道你们只看这儿)

#include<iostream>
#include<cmath>
using namespace std;
const int N=1e5+5; 
int n,d,v[N],a[N];
int main()
{
	cin>>n>>d;
	for(int i=1;i<=n-1;i++) cin>>v[i];
	for(int i=1;i<=n;i++) cin>>a[i];
	int min_0=a[1];
	long long duo=0,you,ans=0;
	for(int i=1;i<=n-1;i++)
	{
		//遍历v[N],每一段路,都用最便宜的油走完
		if(min_0>a[i]) min_0=a[i];
		//更新最便宜的油价
		you=ceil((v[i]-duo)*1.0/d);
		ans+=you*min_0;
		duo+=you*d-v[i];//更新多走的路 
	}  
	cout<<ans<<endl;
	return 0;
}

还有一种写法:

#include<iostream>
#include<cmath>
using namespace std;
const int N=1e5+5; 
int n,d,v[N],a[N];
long long sum[N]; 
int main()
{
	cin>>n>>d;
	for(int i=1;i<=n-1;i++){
		cin>>v[i];
		sum[i]=sum[i-1]+v[i];//第i个站点,到起点的距离 
	}
	for(int i=1;i<=n;i++) cin>>a[i];
	//从1号出发,去下一个比他油价低的加油站
	int now=a[1];
	long long pass=0,dis,you,ans=0;//走过的路 
	for(int i=2;i<=n-1;i++)
	{
		//判断什么,就到哪里
		if(now>a[i])
		{//买油,整数升
		//计算花费?走多远->买多少油->花多少钱
		dis=sum[i-1]-pass;
		//sum[i]表示,i距离起点的距离
		you=ceil(dis*1.0/d);//向上取整,多买一升
		ans+=you*now;
		//更新油价
		now=a[i]; 
		pass+=you*d; 
		} 
	 }//还需要最后走到终点
	dis=sum[n-1]-pass;
	//sum[i]表示i距离起点的距离 
	you=ceil(dis*1.0/d);//向上取整,多买一升
	ans+=you*now; 
	cout<<ans<<endl;
	return 0;
}

AC

第三题(折磨我三个小时我特么直接放弃)

赛后死磕出来了:

先讲讲骗分:

#include<iostream>
#include<cmath>
using namespace std;
const int N=1e5+5;
int t,m,a,b,c;
int main()
{
	cin>>t>>m;
	while(t--)
	{
		cin>>a>>b>>c;
		int r=b*b-4*a*c;
		if(r<0) cout<<"NO"<<endl;
		else if(b==0&&c==0) cout<<0<<endl;
		else{
			int x1=(-b+sqrt(r))/(2*a);
			int x2=(-b-sqrt(r))/(2*a);
			cout<<max(x1,x2)<<endl;
		}
	}
	return 0;
}

50分~(就是考试时一分都没骗到QAQ)

上面是玄学解法下面是满分解法:

#include<bits/stdc++.h>
using namespace std;
int t,m,a,b,c;
int gcd(int a,int b){
    if(a%b==0) return b;
    return gcd(b,a%b);
}
int main(){
    cin>>t>>m;
    while (t--)
    {
        cin>>a>>b>>c;
        int r=b*b-4*a*c;
        if(r<0) cout<<"NO";
        else{//输出解
            //预处理,化简sqrt(r)
            int b2=1;
            for(int i=2;i*i<=r;i++){
                while (r%(i*i)==0)
                {
                    r/=(i*i);
                    b2*=i;
                }
            }
            int aa=2*a,bb=-b;
            //方便变量运算,(bb+b2sqrt(r0))/aa
            //保证+ b2sqrt(r0)/aa更大,因为aa一定>0
            if(aa<0) aa=-aa,bb=-bb;
            //化简后,srqt内为1,直接省略根号
            //并将分子合并。(bb+b2)/2a
            if(r==1) bb+=b2;
            //  bb/aa+b2sqrt(r0)/aa;
            int gc1=gcd(abs(bb),aa);
            int gc2=gcd(b2,aa);
            if(r==0||r==1){//不输出sqrt
                if(bb%aa==0) cout<<bb/aa;
                else cout<<bb/gc1<<'/'<<aa/gc1;
            }
            else{
                if(bb!=0){//输出q1部分
                    if(bb%aa==0) cout<<bb/aa<<'+';
                    else cout<<bb/gc1<<'/'<<aa/gc1<<'+';
                }
                //输出q2部分
                if(b2/gc2!=1) cout<<b2/gc2<<'*';
                cout<<"sqrt("<<r<<')';
                if(aa/gc2!=1) cout<<'/'<< aa/gc2;
            }
        }
        cout<<endl;
    }
    return 0;
}

第四题关于图论,在结尾给大家放一下题

(不要问为什么没有代码,因为这个啥必不会)

(看我做的这么辛苦,不妨点个赞和关注再走?)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值