csp-j普及组历年经典题及思路和解析

1.[CSP-J2019] 数字游戏

        1.链接  

​​​​​传送门icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P5660

          2.思路

                本蒟蒻一看到这题,立马想到暴力求解:循环八遍,输入一个string,一位位判断是否为一,输出。

        3.代码

#include
using namespace std;
main(){
    string a;
    int b=0;
    cin>>a;
    for(int i=0;i<=7;i++){
        if(a[i]=='1'){
            b++;
        }
    }
    cout<

 2.[CSP-J 2019] 公交换乘

        1.链接  

传送门icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P5661

          2.思路

        这是一道很有意境感的模拟题

        我们需要算出小轩花费最少的钱,关键就在找出可以使用优惠票的时候

        1,:在遇到乘坐地铁时,把价格和时间存下

        2:遇到公交车时,只要本次公交车与乘坐地铁的时间间隔不超过45分钟&&需要的钱不超过地铁钱,就可以使用优惠券,(这将是我们对于是否可以免费乘坐的依据,也是判断语句)

        还要注意一下超时问题,如果每次都从第一次地铁开始模拟的话,是肯定会超时的,所以当我们发现了已经超过了45分钟的话,就把超出45分钟的票移出循环列表

        这样就可以把这道题模拟出来

        3.代码

#include 
using namespace std;
int n,ans,t1[100005],sum,Price[100005];
struct BY {
	int by,price,t;
} T[100005];
main() {
	//freopen("bus.in","r",stdin);
	//freopen("bus.out","w",stdout);
	cin>>n;
	for(int i=1; i<=n; i++) {
		cin>>T[i].by>>T[i].price>>T[i].t;
		if(T[i].by==0) {
			ans+=T[i].price;
			sum++;
			t1[sum]=T[i].t;
			Price[sum]=T[i].price;
		} else {
			int f=-1;
			for(int j=sum; T[i].t-t1[j]<=45 && j>=1; j--) {
				if(Price[j]>=T[i].price) f=j;
			}
			if(f==-1) ans+=T[i].price;
			else Price[f]=0;
		}
	}
	cout<

  3. [CSP-J2020] 优秀的拆分

        1.链接  

传送门icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P7071

          2.思路

把 n 转换为2进制,每取到一位"1"就变成十进制,再从大到小输出即为 n 优秀的拆分。

        3.代码

#include 
using namespace std;
long long n,a[35],idx;
void change(int b) {
	int res=0;
	while(b) {
		if (b&1) a[res]=pow(2,res);
		res++;
		b>>=1;
	}
	idx=res;
}
main() {
	cin>>n;
	if (n%2==1) {
		cout<<"-1";
		return 0;
	}
	change(n);
	for(int i=idx; i>=1; i--)
		if (a[i]!=0) cout<

  4.[CSP-J2020] 直播获奖

        1.链接  

传送门icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P7072

          2.思路

        

        其实我们只要观察一下数据范围就会发现,分数的范围非常小!(只有600)

        于是就顺理成章的想到了桶排。

        思路非常简单,而且不存在超时。

        没什么好说的.

        3.代码

#include
using namespace std;
int t[605];
int n,w;
main() {
	int x;
	cin>>n>>w;
	for(int i=1; i<=n; i++) {
		cin>>x;
		t[x]++;
		int sum=0;
		for(int j=600; j>=0; j--) {
			sum+=t[j];
			if(sum>=max(1,i*w/100)) {
				cout<

   5.[CSP-J 2021] 分糖果

        1.链接  

传送门icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P7909

          2.思路

        

       

很容易想到暴力,把 l 到 r 全扫一遍就行,得分 70。

但是可以发现,在(l,r) 这一段里,只有两种情况:

  • 包含一个 x 使得 n 可以整除 x。
  • 如果不包含那么r 一定是最大的,因为(l,r) 中若没有x∣n 那么这一段中每一个数  mod n 的值一定递增并在r 处达到段内的顶峰。

所以我们可以检查 l+(n−lmodn−1) 的值(即使得 modn=n−1 最小的 x)是否在区间内,如果是可以直接输出 n−1,否则输出r mod n。

        3.代码

#include 
using namespace std;
int n,l,r;
main(){
	cin>>n>>l>>r;
	int k=l%n;
	if(l+(n-1-k)<=r){
		cout<

    6. [CSP-J 2022] 乘方

        1.链接 

传送门icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P8813

          2.思路

        

       

假如直接使用 pow 函数计算结果极有可能会出现爆上限的情况,导致结果变为负数,无法判断是否大于 10^9

此时从题目中可以想到模拟乘方的计算过程:将a 累乘 b 次。假如在乘的过程中结果已经大于 109,就可以直接输出 −1,结束程序。假如累乘完 b 次后仍然没有结束程序,就可以输出计算的结果。

在 a>1 的情况下最多累乘 31 次就会结束循环,没有超时风险。但是在a=1 的情况下会执行 b 次,最劣要执行 109 次,有超时风险,并且显然在a=1 的情况下乘方一定为1,所以可以加上特判,在a=1 时直接输出1。这样可以保证不超时。

        3.代码

#include 
using namespace std;
int a, b;
long long ans=1,c;
long long aaa (int a,int b) {
	if(a==1) {
		c=1;
		return c;
	}
	for(int i=1; i<=b; ++i) {
		ans*=a;
		if(ans>1e9) {
			c=-1;
			return c;
		}
	}
	return ans;
}
main() {
	cin>>a>>b;
	long long d=aaa(a,b);
	cout<

csp-j普及组历年经典题及思路和解析_第1张图片

跪求点赞

你可能感兴趣的:(算法,c++,数据结构)