CSP第一题刷题记录

53 阅读17分钟

202312-1仓库规划
西西艾弗岛上共有 n 个仓库,依次编号为 1⋯n。每个仓库均有一个 m 维向量的位置编码,用来表示仓库间的物流运转关系。

具体来说,每个仓库 i 均可能有一个上级仓库 j,满足:仓库 j 位置编码的每一维均大于仓库 i 位置编码的对应元素。比如编码为 (1,1,1) 的仓库可以成为 (0,0,0) 的上级,但不能成为 (0,1,0) 的上级。如果有多个仓库均满足该要求,则选取其中编号最小的仓库作为仓库 i 的上级仓库;如果没有仓库满足条件,则说明仓库 i 是一个物流中心,没有上级仓库。

现给定 n 个仓库的位置编码,试计算每个仓库的上级仓库编号。

#include <iostream>
using namespace std;
int main() {
	int n, m, i, j, k;
	cin>>n>>m;
	int a[n][m] = {0};//n行m列
	for(i=0; i<n; i++) {
		for(j = 0; j < m; j++) {
			cin>>a[i][j];
		}
	}
	for(i=0; i<n; i++) {//取第一组 
		int res = 0;
		for(j = 0; j < n; j++) {//遍历找出第一组的上层 
			bool flag = true; //true表示是上层 
			if(i != j) {//再选的第二组不能是第一组 
				for(k = 0; k < m; k++) {//遍历第二组的各位 
					if(a[i][k] >= a[j][k]) {//如果存在一位比第一组小
						flag = false;
						break;//那么第二组就不是第一组的上一层 
					} 
			   }
				if(flag) {
					res = j + 1;
					//若结束遍历时,即第二组各位都大于第一组,那么第二组就是第一组的上层
					break;//退出遍历找出第一组的上层的循环 
				} 
				//如果flag=false,一直没找到上层,那么res=0,表示为中心仓库 
			}

		}
		cout<<res<<endl;
	}
	
}

202309-1坐标变换(其一) 第一道不看解析AC的题!
对于平面直角坐标系上的坐标 (x,y),小 P 定义了一个包含 n 个操作的序列 T=(t1,t2,⋯,tn)。其中每个操作 ti(1≤i≤n)包含两个参数 dxi 和 dyi,表示将坐标 (x,y) 平移至 (x+dxi,y+dyi) 处。

现给定 m 个初始坐标,试计算对每个坐标 (xj,yj)(1≤j≤m)依次进行 T 中 n 个操作后的最终坐标。

#include <iostream>
using namespace std;
int main() {
	int n, m, i, j, dxsum = 0, dysum = 0;
	cin>>n>>m;
	int dx[n], dy[n], x[m], y[m];
	for(i = 0 ; i < n; i++) {
		cin>>dx[i]>>dy[i];
	}
	for(j = 0 ; j < m; j++) {
		cin>>x[j]>>y[j];
	}
	for(i = 0; i < n; i++) {
		dxsum += dx[i];
		dysum += dy[i];
	}
	for(j = 0; j < m; j++) {
		printf("%d %d\n", x[j] + dxsum, y[j] + dysum);
	}
	return 0;
}

202305-1重复局面<
国际象棋每一个局面可以用大小为 8×8 的字符数组来表示,其中每一位对应棋盘上的一个格子。六种棋子王、后、车、象、马、兵分别用字母 kqrbnp 表示,其中大写字母对应白方、小写字母对应黑方。棋盘上无棋子处用字符 * 表示。两个字符数组的每一位均相同则说明对应同一局面。

现已按上述方式整理好了每步棋后的局面,试统计每个局面分别是第几次出现。

#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main() {
	int n;
	cin>>n;
	string chess[110];
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= 8; j++) {
			string temp;
			cin>>temp;
			chess[i] = chess[i] + temp;//每输入8行字符串,合并成一个大字符串chess 
		}
	}
	for(int i = 1; i <= n; i++) {
		int count = 1;
		for(int k = 1; k < i; k++) {//遍历该字符串以前的所有字符串 
			if(chess[k] == chess[i])count++;//相同局数 
			//string判定相等的方法 
		}
		cout<<count<<endl; 		
	} 
	return 0;
	
}

202303-1田地丈量
西西艾弗岛上散落着 n 块田地。每块田地可视为平面直角坐标系下的一块矩形区域,由左下角坐标 (x1,y1) 和右上角坐标 (x2,y2) 唯一确定,且满足 x1<x2、y1<y2。这 n 块田地中,任意两块的交集面积均为 0,仅边界处可能有所重叠。

最近,顿顿想要在南山脚下开垦出一块面积为 a×b 矩形田地,其左下角坐标为 (0,0)、右上角坐标为 (a,b)。试计算顿顿选定区域内已经存在的田地面积。

#include <iostream>
#include <string>
#include <stdio.h>
#include <math.h>
using namespace std;
int main() {
	int n, a, b, i;
	cin>>n>>a>>b;
	int x1, y1, x2, y2, sum = 0;
	for(i = 0; i < n; i++) {
		cin>>x1>>y1>>x2>>y2;
		int xk, yk, xt, yt;
		if((0<=x1)&&(x1<=a)) xk = x1;
		if(x1<0) xk = 0;
		if(x1>a)continue;
		
		if((0<=y1)&&(y1<=b)) yk = y1;
		if(y1<0) yk = 0;
		if(y1>b)continue;
		
		if((0<=x2)&&(x2<=a)) xt = x2;
		if(x2<0) continue;
		if(x2>a) xt = a;
		
		if((0<=y2)&&(y2<=b)) yt = y2;
		if(y2<0) continue;
		if(y2>b) yt = b;
		
		if((xt>=xk) && (yt >= yk))
			sum += (xt-xk)*(yt-yk);
	}
	cout<<sum;
	return 0;
	
}

202212-1现值计算
评估一个长期项目的投资收益,资金的时间价值是一个必须要考虑到的因素。简单来说,假设银行的年利率为 5%,那么当前的 100 元一年后就会变成 105 元,两年后变成 110.25 元。因此,现在收到 100 元比两年后收到 100 元收益更多,两年后再支出 100 元会比立刻支出 100 元更加划算。

基于上述分析,我们使用如下的模型来衡量时间价值:假设银行的年利率为 i,当前(第 0 年)的 x 元就等价于第 k 年的 x×(1+i)k 元;相应的,第 k 年的 x 元的当前价值实际为 x×(1+i)−k 元。

现给出某项目未来 n 年的预计收入支出情况,在将所有款项转换为当前价值后,试计算该项目的总收益。

这题AC!

#include<iostream>
#include<cmath>
using namespace std;
int main() {
	int n, a[51];
	double i, sum = 0;
	cin>>n>>i;
	for(int j = 0; j < n+1; j++) {
		cin>>a[j];
		sum += a[j] * pow(1+i, -j);
	}
	cout<<sum;
	return 0;
}

202206-1归一化处理 1726848186864.png

#include <iostream>
#include <cmath>
#include <iomanip>  // 用于 std::fixed 和 std::setprecision

using namespace std;

int main() {
    int n, a[1000];
    cin >> n;
    int sum = 0;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        sum += a[i];
    }

    double f[1000], D = 0.0;
    double ave = sum * 1.0 / n;
    for (int i = 0; i < n; i++) {
        D += pow(a[i] - ave, 2);
    }
    D = D / n;
    
    for (int i = 0; i < n; i++) {
        f[i] = (a[i] - ave) * 1.0 / sqrt(D);
    }
    
    // 设置输出的小数位数
    cout << fixed << setprecision(6);
    
    for (int i = 0; i < n; i++) {
        cout << f[i] << endl;
    }
    
    return 0;
}

202203-1未初始化警告 1726848166545.png

#include<iostream>
using namespace std;
int main() {
	int n, k;
	cin>>n>>k;
	bool st[100000] = {false};
	st[0] = true;//下标为0标记为常量
	int sum = 0;
	for(int i = 1; i <= k; i++) {
		int x, y;
		cin>>x>>y;
		if(!st[y]) sum++;//若右值未被赋值过 
		st[x] = true;//将左值标记为赋值过 
	} 
	cout<<sum<<endl; 
}


202112-1序列查询 1726848145331.png 下面这个做法是超时的!!

#include<iostream>
using namespace std;
int main() {
	int n, N;
	cin>>n>>N;
	int A[n+1], f[N];//A[n+1]注意别写成A[n] 
	A[0] = 0;
	for(int i = 1; i <= n; i++) {
		cin>>A[i];
	}
	int sum = 0; 
	for(int x = 0; x < N; x++) {//x和i的循环里外层别反了,是拿着x找i 
		for(int i = 1; i <= n; i++) {
			if(A[i-1] < x && x < A[i] || x == A[i-1]) {
				f[x] = i-1;
				break;
			}
			else if(A[n] < x || A[n] == x) {//不要用|位运算符,要用||或 
				f[x] = n;
				break;
			}
		}
		sum += 	f[x];
	}
	cout<<sum;
	return 0;
}

正确做法:CSP 202112-1 序列查询(详解)_202112-1cps-CSDN博客

#include <stdio.h>
int main()
{
	//n,代表下一行输入n个数,N代表共有N个序号,注意从0开始
	int n, N;
	
	scanf("%d %d", &n ,&N);
	int B[N] = {0};
	
	int i, j;
	int sum = 0;

	//注意A[0]固定为0,所以从A[1]开始存,到A[n]结束: 
	for(i=1; i<=n; i++)  
	{
		scanf("%d", &j); 
		B[j]++;  //标记出要变的位置,暂时用 B 记录
	}
	
	
	for(i=1; i<N; i++) //B[0] = 0;
	{
		B[i] = B[i] + B[i-1]; //求出真正的数组 B
		sum = sum + B[i];  //求和
	}
		
	printf("%d",sum);
	return 0;
 } 

202104-1灰度直方图 1726848120495.png

#include<iostream>
using namespace std;
int main() {
	int n, m, L;
	cin>>n>>m>>L;
	int A[n][m];
	int h[L] = {0};
	for(int i = 0; i < n; i++) {
		for(int j = 0; j < m; j++) {
			cin>>A[i][j];
			int x = A[i][j];
			h[x]++;
		}
	}
	for(int i = 0; i < L; i++) {
		if(i == L-1)cout<<h[i];
		else cout<<h[i]<<" ";
	}
	return 0;

}

202012-1期末预测之安全指数 1726848086676.png

#include<iostream>
using namespace std;
int main() {
	int n, w[100000], s[100000];
	cin>>n;
	int t[100000], sum = 0;
	for(int i = 0; i < n; i++) {
		cin>>w[i]>>s[i];
		t[i] = w[i] * s[i];
		sum += t[i];
	}
	if(sum <= 0)cout<<0;
	else cout<<sum;
	return 0;

}

202009-1称检测点查询
某市设有 n 个核酸检测点,编号从 1 到 n,其中 i 号检测点的位置可以表示为一个平面整数坐标 (xi,yi)。 为方便预约核酸检测,请根据市民所在位置 (X,Y),查询距其最近的三个检测点。
多个检测点距离相同时,编号较小的视为更近。 重点:vector,sort()

#include<iostream>
#include<cmath>
#include<algorithm>//sort
#include<vector>
using namespace std;

// 自定义比较函数,首先按距离排序,距离相同时按编号排序
bool compare(const pair<int, int>& a, const pair<int, int>& b) {
    if (a.first == b.first) {
        return a.second < b.second; // 如果距离相同,比较编号
    }
    return a.first < b.first; // 否则,比较距离
    //a<b返回true 从小到大排 
}

int main() {
    int n, X, Y;
    cin >> n >> X >> Y;
    int x[n], y[n];
    for (int i = 0; i < n; i++) {
        cin >> x[i] >> y[i];
    }
    vector< pair<int, int> > t(n); // 使用pair存储距离和编号
    for (int j = 0; j < n; j++) {
        t[j].first = (pow((X - x[j]), 2)) + pow((Y - y[j]), 2);
        t[j].second = j;
    }
    sort(t.begin(), t.end(), compare); // 根据自定义比较函数排序

    cout << t[0].second + 1 << endl;
    if (t.size() > 1) cout << t[1].second + 1 << endl;
    if (t.size() > 2) cout << t[2].second + 1 << endl;

    return 0;
}

201312-1出现次数最多的数
给定n个正整数,找出它们中出现次数最多的数。如果这样的数有多个,请输出其中最小的一个。

#include <iostream>
using namespace std;
int main()
{   
    int n;
    cin>>n;
    int a[1024];
    for(int i=1;i<=n;i++)
    cin>>a[i];
    int b[10010]={0};//数组下标存这个数,数组值存这个数出现的次数
	for(int i=1;i<=n;i++)
    {   
        int b_i=a[i];//值 
	    b[b_i]++;//出现a[i]的次数 
    }
	int max=0;  //默认次数是0 
	int ans;        
	for( int i=1;i<10010;i++)
	{
		if(b[i]>max&&b[i]!=0) // 大于保证了输出的是最多并且是最多的中最小的 
		{
			 max=b[i]; //这个就是最大次数 
			 ans=i;
		}
	     
	}
	cout<<ans<<endl;
	return 0;	                                                           
}

202006-1线性分类器 1726849606057.png

#include<iostream>
using namespace std;

int x\[1010],y\[1010];
char s\[1010];

int main()
{
int n,m,a,b,c;;
cin>>n>>m;
for(int i=0;i\<n;i++)
cin>>x\[i]>>y\[i]>>s\[i];

    for(int i=0;i<m;i++)
    {
    	cin>>a>>b>>c;//θ0=a,θ1=b,θy =c
    	//先标定A、B在直线哪侧 
    	int A,B;
    	if(s[0]=='A')
    	{
    		if(a+b*x[0]+c*y[0]>0)
    			A=1,B=-1;//A类上面1,下面-1 
    		else
    			A=-1,B=1;
    	}
    	else
    	{
    		if(a+b*x[0]+c*y[0]>0)//B类下1上-1 
    			A=-1,B=1;
    		else
    			A=1,B=-1;
    	}
    	int t=1;//代表多少点符合分类 
    	for(int j=1;j<n;j++)
    	{
    		if(s[j]=='A')
    		{
    			if( ((a+b*x[j]+c*y[j])*A)>0 )
    				t++;
    			else
    				break;
    		}	
    		else if(s[j]=='B')
    		{
    			if( ((a+b*x[j]+c*y[j])*B)>0 )
    				t++;
    			else
    				break;
    		}
    	}
    	if(n==t)
    		cout<<"Yes"<<endl;
    	else 
    		cout<<"No"<<endl;
    }
    return 0;
}

201912-1报数
甲乙丙丁决定玩一个报数的游戏来打发时间。游戏规则为四个人从1开始轮流进行报数,但如果需要报出的数是7的倍数或含有数字7则直接跳过。
此外大家约定,在总共报出了n个数后(不计入被跳过的数)游戏结束。现在需要你来帮忙统计,游戏过程中每个人各自跳过了几次。

#include<iostream>
using namespace std;

int main() {
    int n, a[4] = {0}, k;
    cin >> n;
    int j = 0, count = 0;
    for (int i = 1; count < n; i++) { // 直到报出n个数为止
        int num = i; // 用于检查数字中是否包含7
        bool skip = false; // true为需要跳 
        
        // 检查是否是7的倍数
        if (i % 7 == 0) skip = true;
        // 检查数字中是否包含7
        else {
            while (num > 0) {
                if (num % 10 == 7) {
                    skip = true;
                    break;
                }
                num /= 10;
            }
        }
        
        
        if (!skip) {// 如果不需要跳过
            count++; // 报数增加
        } else {
            a[j]++; // 跳过增加
        }
        
        j++; // 切换到下一个人
        if (j == 4) j = 0; // 如果超过4个人,则回到第一个人
    }
    
    for (k = 0; k < 4; k++)
        cout << a[k] << endl; 
    
    return 0;
}

201909-1小明种苹果

1726908672106.png

#include<iostream>
#include<cmath>
using namespace std;

int main() {
    int N, M;
    cin>>N>>M;
    int a[N][M+1];//
    int T = 0;
    int s[N+1] = {0};
    int max = s[0], P, k = 0;
	for(int i = 0; i < N; i++) {//
		for(int j = 0; j <= M; j++) {//
			cin>>a[i][j];
			T += a[i][j];
			if(j) s[i] += a[i][j];
		}
		if(max > s[i]) {
			max = s[i];
			k = i+1;//
		}
	}
	P = abs(max);
	cout<<T<<" "<<k<<" "<<P;
    return 0;
}

201903-1小中大

1726909901308.png

#include<iostream>
#include<cmath>
using namespace std;

int main() {
    int n;
    cin>>n;
    int a[n], Mid;
    for(int i = 0; i < n; i++) {
    	cin>>a[i];
	}
	int max = (a[0]>a[n-1]) ? a[0] : a[n-1];
	int min = (a[0]<a[n-1]) ? a[0] : a[n-1];

	    if (n % 2 == 1) {
        Mid = a[ n / 2];
        printf("%d %d %d\n", max, Mid, min);
    }
    else {
        double mMid;
        int p = a[n / 2];
        int q = a[n / 2 - 1];
        if (abs(p + q) % 2 == 1) { // 中间两个数的和为奇数会出现分数,C++向0取整
            mMid = (p + q) / 2.0 ;
            printf("%d %.1f %d\n", max, mMid, min);
        }
        else {
            Mid = (p + q) / 2;
            printf("%d %d %d\n", max, Mid, min);
        }
    }

    return 0;
}

201809-1卖菜
在一条街上有n个卖菜的商店,按1至n的顺序排成一排,这些商店都卖一种蔬菜。
第一天,每个商店都自己定了一个价格。店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。
注意,编号为1的商店只有一个相邻的商店2,编号为n的商店只有一个相邻的商店n-1,其他编号为i的商店有两个相邻的商店i-1和i+1。
给定第一天各个商店的菜价,请计算第二天每个商店的菜价。

#include<iostream>
#include<cmath>
using namespace std;

int main() {
    int n, i;
    cin>>n;
    int a[n], b[n];
    double t;
    for(int i = 0; i < n; i++) {
    	cin>>a[i];
	}
	for(i = 0; i < n; i++) {
		if(i ==0)  {
			t = (a[i] + a[i+1])/2;
			b[i] = t;
		}
		else if(i == n-1) {
			t = (a[i] + a[i-1])/2;
			b[i] = t;
		}
		else {
			t = (a[i-1] + a[i] + a[i+1])/3;
			b[i] = t;
		}
	}
	for(i = 0; i < n; i++) {
		cout<<b[i]<<" ";
	}

    return 0;
}

201803-1跳一跳 近来,跳一跳这款小游戏风靡全国,受到不少玩家的喜爱。
简化后的跳一跳规则如下:玩家每次从当前方块跳到下一个方块,如果没有跳到下一个方块上则游戏结束。
如果跳到了方块上,但没有跳到方块的中心则获得1分;跳到方块中心时,若上一次的得分为1分或这是本局游戏的第一次跳跃则此次得分为2分,否则此次得分比上一次得分多两分(即连续跳到方块中心时,总得分将+2,+4,+6,+8...)。
现在给出一个人跳一跳的全过程,请你求出他本局游戏的得分(按照题目描述的规则)。

#include<iostream>
using namespace std;

int main() {
    int a[30];
    int i, s = 0;
    int sum[30] = {0}; // 用于存储每一步的得分

    for(i = 0; i < 30; i++) {
        cin >> a[i];
        if(a[i] == 1) {
            sum[i] = 1;
        } 
		else if(a[i] == 2) {
            if(i == 0 || a[i-1] == 1)
                sum[i] = 2;
			else {
                sum[i] = 2 * (sum[i-1] / 2 + 1);
            }    
    }
        else if(a[i] == 0)
            break;
}

    for(i = 0; i < 30; i++) {
        s += sum[i];
    }
    cout << s;

    return 0;
}

201712-1最小差值
给定n个数,请找出其中相差(差的绝对值)最小的两个数,输出它们的差值的绝对值。

#include<iostream>
#include<algorithm>
using namespace std;

int main() {
	int n, i;
	cin>>n;
	int a[n], b[n-1], min=100001;//
	for(i = 0; i < n; i++) {
		cin>>a[i];

	}
	sort(a, a+n, greater<int>());//
	for(i = 0; i < n-1; i++) {
			b[i] = a[i]-a[i+1];//
			if(b[i] < min) {
			min = b[i];
		}
	}
	cout<<min;
	
	

    return 0;
}

201709-1打酱油
小明带着N元钱去买酱油。酱油10块钱一瓶,商家进行促销,每买3瓶送1瓶,或者每买5瓶送2瓶。请问小明最多可以得到多少瓶酱油。

#include<iostream>
using namespace std;

int main() {
    int sum = 0, t;
    int N;
    cin >> N;

    // 计算最多可以买多少瓶
    int max_bottles = N / 10;

    // 先尽可能多地使用买5瓶送2瓶的优惠
    int bottles_with_5 = max_bottles / 5;
    sum += bottles_with_5 * 7; // 每买5瓶送2瓶,总共得到7瓶

    // 剩余的瓶数
    t = max_bottles % 5;

    // 使用买3瓶送1瓶的优惠
    int bottles_with_3 = t / 3;
    sum += bottles_with_3 * 4; // 每买3瓶送1瓶,总共得到4瓶

    // 最后剩余的瓶数
    t = t % 3;
    sum += t; // 直接购买剩余的瓶数

    cout << sum;

    return 0;
}

我的方法为啥不行?

#include<iostream>
using namespace std;
int main() {
	int sum = 0, t;
	int N;
	cin>>N;
	N = N/10;
	t = N;
	while(t>=3){
		if(N%5!=0) {
			sum += (N/5)*7;
			t = N%5;
		}
		else if(N%3 != 0) {
			sum += (N/3)*4;
			t = N%3;
		}
	}
	sum+=t;

	cout<<sum;

    return 0;
}

201703-1分蛋糕
小明今天生日,他有n块蛋糕要分给朋友们吃,这n块蛋糕(编号为1到n)的重量分别为a1, a2, …, an。小明想分给每个朋友至少重量为k的蛋糕。小明的朋友们已经排好队准备领蛋糕,对于每个朋友,小明总是先将自己手中编号最小的蛋糕分给他,当这个朋友所分得蛋糕的重量不到k时,再继续将剩下的蛋糕中编号最小的给他,直到小明的蛋糕分完或者这个朋友分到的蛋糕的总重量大于等于k
请问当小明的蛋糕分完时,总共有多少个朋友分到了蛋糕。

#include<iostream>
#include<vector>
using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    int t = 0; // 用于跟踪当前分配的蛋糕编号
    int friends = 0; // 已经分到蛋糕的朋友数量
    int sum = 0; // 用于跟踪当前朋友得到的蛋糕总重量

    while (t < n) { // 只要还有蛋糕可以分配
        sum = 0; // 重置当前朋友得到的蛋糕总重量
        while (t < n && sum < k) { // 当还有蛋糕可以分配且当前朋友得到的蛋糕总重量小于k
            sum += a[t]; // 分配蛋糕
            t++; // 移动到下一个蛋糕
        }
        if (sum >= k || t == n) { // 如果当前朋友得到了足够的蛋糕,或者没有更多的蛋糕可以分配
        ////如果最后一个小朋友获得的蛋糕重量小于 k 并且没有更多的蛋糕可以分配,这个小朋友也要被计入得到蛋糕的小朋友数量中
            friends++; // 增加分到蛋糕的朋友数量
        }
    }

    cout << friends; // 输出分到蛋糕的朋友数量

    return 0;
}


或者

#include <iostream>
#include<cstdio>
using namespace std;
int a[1001];     //注意a[i]的大小
int main()
{
    int n,k,p=0,sum=0,s=0; //p统计人数,sum记录蛋糕重量,s可有可无,为了保存sum
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int j=0;j<n;j++)
    {
        sum += a[j];
        s = sum;
        if(sum>=k)
        {
            p++;
            sum = 0;
        }
    }
    printf("%d",s<k?p+1:p);

}