2024年8月21日 CSP-J 2023 个人练习总结

T1 小苹果

题目大意

小明小红是损友,小红偷小明的苹果,但是不想让他看出来,于是间隔着偷,每次间隔两个,然后把剩下的拼起来,问一共要偷几次,第n个苹果是几次偷完的。

思路

首先看到这个题目,我们直接想到暴力模拟,没错用最简单的模拟就直接能过,设定好终止条件就好。

代码

比较简单,100pt:

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;

int n,x;
int ans,cnt;


int main(){
	
    cin >> n;
	x=n;
	
	while(x){
		cnt++;
		x-=(x+2)/3;
	}
	cout << cnt << ' ';
    
	while(1){
		ans++;
		if(n%3==1)break;
		n-=(n+2)/3;
	}
	cout << ans << endl;
}

T2 公路 

题目大意

小明开车自驾游,沿着一条公路跑,每加一点油就能跑一段路,问从1~n最少需要加多少油。

思路

首先注意到从1~n,吓得我一激灵想要用dp,但是想想不对,这道题显然是可以贪心的,但是贪心的方式不一样,我自己写出来的时候都感觉不像贪心,看题解说这叫做反悔贪心,简单来说就是没油了就从前面的最便宜的地方加油,可以理解为小明有一个传送器,可以跑到前面加一次油再传送回来(不然就要跑冤枉路了),很好理解的算法,代码也不长。

代码

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


const int N = 1e5 + 10;

int v[N], a[N];
int n, d;
int main() {
    scanf("%d%d", &n, &d);
    for (int i = 1; i < n; i++) scanf("%d", &v[i]);
    int mi = 1e9;
    LL ans = 0, s = 0;
    for (int i = 1; i < n; i++) {
        scanf("%d", &a[i]);
        s += v[i];
        mi = min(mi, a[i]);
        if (s > 0) {
            ans += (s + d - 1) / d * mi;
            s -= (s + d - 1) / d * d;
        }
    }
    printf("%lld\n", ans);
    return 0;
}

T3 一元二次方程

题目大意

围绕着一元二次方程求根公式展开一系列非常复杂的模拟,完全说不清楚,直接贴上原题链接:

P9750 [CSP-J 2023] 一元二次方程 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路

一道非常典型,非常豪堪,非常令人眼前一黑的,非常大的模拟题!

首先我们发现这道题是要不断的计算计算再计算,计算出来的情况怎么搞都完全不会超过时间限制,因为数据范围只有5000次询问而最大的M也就只有1000,所以考虑直接进行模拟,模拟的过程中需要不断的特判,这一题我做出来了结果传上去只有60pt,后来测样例找到了一个bug,de掉了以后仍然是60pt,于是我怒看题解,题解的代码比我少一半……好吧,我干脆直接把我的代码和题解的代码都贴上来得了。

代码

我的 60pt:
#include<bits/stdc++.h>
#define endl '\n'
//#define int double
using namespace std;


int t,m,a,b,c;


bool check(double n){
	int m=int(n);
	if(n == m){
		return 1;
	}
	return 0;
}


int f(int n){
	for(int i=sqrt(n); i>=2; i--){
		if(n%(i*i) == 0){
			return i;
		}
	}
	return 1;
}



int main(){
//	freopen("uqe.in","r",stdin);
//	freopen("uqe.out","w",stdout);
	cin >> t >> m;
	for(int i=1; i<=t; i++){
		cin >> a >> b >> c;
		if(a < 0){
			a = -a;
			b = -b;
			c = -c;
		}
		if(b*b-4*a*c < 0){
			cout << "NO" << endl;
			continue;
		}
		else{
			int z = b*b-4*a*c;
//			cout<<"z="<<z<<endl;
			double x = (b*(-1)+sqrt(z))/(2*a);
//			cout<<"x="<<x<<endl;
			if(check(sqrt(z)) == 1){
				if(check(x) == 1){
					if(x == 0){
						cout << 0 << endl;
					}
					else{
						cout << x << endl;
					}
				}
				else{
					int n = -b+sqrt(z);
					int m = 2*a;
//					cout<<"__gcd(n,m)="<<__gcd(n,m)<<endl;
					cout << n/abs(__gcd(n,m)) << "/" << m/abs(__gcd(n,m)) << endl;
				}
			}
			else{
				double q1 = (b*1.0/(2*a))*-1;
//				cout<<"q1="<<q1<<endl;
				double q2 = 1/(2*a);
//				cout<<"q2="<<q2<<endl;
				int d = f(z);
//				cout<<"d="<<d<<endl;
				if(q1 == -0){
					q1 = 0;
				}
				if(q1 != 0){
					if(check(q1) == 1){
						cout << q1;
					}
					else{
						int n = (b*1.0)*-1;
						int m = 2*a;
//						cout<<"__gcd(n,m)="<<__gcd(n,m)<<endl;
						cout << n/abs(__gcd(n,m)) << "/" << m/abs(__gcd(n,m));
					}
					cout<<"+";
				}
				if(q2 == 1){
					cout<<sqrt(z)<<endl;
				}
				else if(check(q2) == 1){
					double s=d*1.0/(2*a);
					if(check(s) == 1){
						if(s == 1) cout << "sqrt(" << z/(d*d) << ")" << endl;
						else cout << s << "*sqrt(" << z/(d*d) << ")" << endl;
					}
					else{
						if(__gcd(d,2*a) == 1){
							if(d != 1)
							{
								cout<<d <<"*";
							}
							cout << "sqrt(" <<z/(d*d)<< ")/"<< 2*a<< endl;
						}
						else{
							cout << "sqrt(" <<z/(d*d)<< ")/"<< 2*a/__gcd(d,2*a)<< endl;
						}
					}
				}
			}
		}
	}
	
}
题解 100pt:(诡异的代码)
#include<bits/stdc++.h> 
using namespace std;
int T,m,a,b,c,d,k,t;
int gcd(int a,int b){//最大公因数
	return b?gcd(b,a%b):a;
}
void Main(){
	cin>>a>>b>>c;
	if(a<0)
		a=-a,b=-b,c=-c;//细节1:分母非负
	d=b*b-4*a*c,k=1;//d是delta
	if(d<0){
		cout<<"NO\n";
		return;
	}//无解
	for(int i=2;i*i<=d;i++)
		while(d%(i*i)==0)
			k*=i,d/=(i*i);//k*sqrt(d)
	if(d==0||d==1){//有理数
		t=abs(gcd(2*a,-b+k*d));//细节2:取绝对值
		cout<<(-b+k*d)/t;
		if(2*a/t!=1)//细节3:分母非1
			cout<<'/'<<2*a/t;
		cout<<'\n';
		return;
	}
	//-b/2a+k*sqrt(d)/2a
	t=abs(gcd(-b,2*a));//细节2
	if(-b/t==0)//细节4:不能有0+xxx
		goto g;
	cout<<-b/t;
	if(2*a/t!=1)//细节3
		cout<<'/'<<2*a/t;
	cout<<'+';
	g:
	t=abs(gcd(k,2*a));//细节2
	if(k/t!=1)//细节5:乘数不为1
		cout<<k/t<<'*';
	cout<<"sqrt("<<d<<')';
	if(2*a/t!=1)//细节3
		cout<<'/'<<2*a/t;
	cout<<'\n';
	return;
}
int main(){/*
	freopen("uqe.in","r",stdin);
	freopen("uqe.out","w",stdout);*/
	for(cin>>T>>m;T;--T)
		Main();//根据某人言,多测函数好
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值