CSP-J模拟赛补题3

日期:2024年10月3日

学号:S14738

一、我的总分:
T1【IP地址(ip)】:100分

T2【是否同构(same)】:60分

T3【箱子(box)】:10分

T4【社恐的聚会(party)】:40分

二、比赛概况:
T1【IP地址(ip)】:

        咱就是说,3天了,第一个AC的题!一读完题就想到了那个用map的“查字典”,思路也是非常OK,很快就写完了。

T2【是否同构(same)】:

        还行吧,写完的时候代码有亿点问题,改了改,感觉while是没问题的,但是要么死循环,要么只循环一次,后来也没再怎么弄。

T3【箱子(box)】:

        第二个做的这个题,感觉做的对,但是忽略了解决最后剩余的箱子,所以没全对。

T4【社恐的聚会(party)】:

        老师说这个题超纲了,光AC代码就70  80行,我蒙了一些判断代码。

三、比赛分析:

T1【IP地址(ip)】:

1、题目大意

        IP地址(Internet Protocol Address)是互联网上用于识别和定位设备的数字标识。它是一种由32位或128位二进制数字组成的地址,在IPv4和IPv6两个主要版本中使用。

        IP地址的主要功能是标识和寻址设备,使其能够在互联网上进行通信。通过将IP地址分配给计算机、服务器、路由器和其他网络设备,数据包可以被正确地发送到目标设备。IP地址还用于确定网络中不同设备的位置,以便进行网络管理和故障排除。

        总之,IP地址是互联网上用于标识和定位设备的数字标识,使设备能够在互联网上进行通信。IP地址的外观根据其版本而有所不同。以下是IPv4和IPv6两个主要版本的IP地址中IPv4地址示例:

  1. 192.168.0.1
  2. 172.16.254.1
  3. 10.0.0.1
  4. 208.75.57.100

        接下来,我们有 N 个设备,每个设备都有它的名称和IPv4地址,现在我们有 Q 个问题,每次我们想知道给出的IPv4地址是哪一个设备?

2、考试思路

       输入 -> 存map -> 输入问题 -> 输出map相对应的设备名

3、讲解后思路

        考试思路也是完全没问题好吧

4、AC代码

#include<iostream>
#include<cstdio>
#include<map>
#include<string>
using namespace std;
//这里类似于查字典的题,要用到 map 
map<string,string> ip;
int n,q;
int main(){
//	freopen("ip.in","r",stdin);
//	freopen("ip.out","w",stdout);
	cin >> n;
	for(int i = 1;i <= n;i++){
		string a,b;
		cin >> a >> b;
		//因为 map 是 <string,string> ,所以可以直接 ip[b] = a 
		ip[b] = a;
	}
	cin >> q;
	//因为有上一步操作,这里可以用 ip[x] 来输出设备 
	for(int i = 1;i <= q;i++){
		string x;
		cin >> x;
		cout << ip[x] << endl;
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

T2【是否同构(same)】:

1、题目大意

        有两个长度为 N 的数组 a,b,我们想知道数组 a 和数组 b 是否是同构数组?

        我们定义两个数组 a,b 同构,则存在一个整数 k,使得 0≤k≤⌊​2​​N​​⌋ ,有保持数组 b 不动的时候,交换数组 a 的前 k 项和后 k 项交换位置,即 swap(a​1​​,a​N−k+1)​​,⋯,swap(a​k​​,a​N​​),使得新的数组 a 完全相等于数组 b 。

2、考试思路

       就是根据自己推的奇偶性以及其他的判断 [捂脸]

3、讲解后思路

        输入 -> 判断相等v存不等 -> 判断不等是否存在v中 -> 输出

4、AC代码

#include<bits/stdc++.h>
using namespace std; 
int a[1000005],b[1000005],v[1000005];
int main(){
//	freopen("same.in","r",stdin);
//	freopen("same.out","w",stdout);
	int t;
	cin >> t;
	while(t--){
		int n;
		bool f = 0;
		cin >> n;
		for(int i = 1;i <= n;i++){
			scanf("%lld",&a[i]);
		}
		for(int i = 1;i <= n;i++){
			scanf("%lld",&b[i]);
		}
		int k = n/2;
		for(int i = 1;i <= k;i++){
			//这里判断 a[i] 是否等于 b[i] 
			if(a[i] != b[i]){
				//等则 v[a[i]] = b[i] 以存储 a[i] 和 b[i] 
				v[a[i]] = b[i];
			}
		}
		for(int i = n;i > k;i--){
			if(a[i] != b[i]){
				//根据上一步操作,没有说明 a[i] 对应的位置不是 b[i] 
				if(v[b[i]] == a[i]){
					continue;
				}else{
					f = 1;
					break;
				}
			}
		}
		if(f){
			printf("No\n");
		}else{
			printf("Yes\n");
		}
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

T3【箱子(box)】:

1、题目大意

        我们有 N 个箱子,每个箱子有自己的重量 w_i,每次我们可以将至多 M 个箱子合并成一个重量为这几个箱子重量和的箱子,花费的体力是这合并的几个箱子的重量和。请问我们将这所有的箱子合并成一个箱子所需要花费的最少体力是多少?

2、考试思路

        输入 -> 合成箱子 -> 输出,中间那一步直接就没想到

3、讲解后思路

        输入 -> 把最后会剩余的箱子先合成 -> 合成箱子 -> 输出

4、AC代码

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
long long n,m,sum;
//最小优先队列 
priority_queue<long long> q;
int main(){
//	freopen("box.in","r",stdin);
//	freopen("box.out","w",stdout);
	cin >> n >> m;
	for(int i = 1;i <= n;i++){
		long long x;
		cin >> x;
		q.push(-x);
	}
	//为了节省体力,先判断到最后能否正好合成一个箱子 
	if((n-m)%(m-1) != 0){
		//如果不能,就先把 (n-m)%(m-1) 个箱子先合成 
		long long r = (n-m)%(m-1),s = 0;
		while(r >= 0){
			s+=-q.top();
			q.pop();
			r--;
		}
		sum+=s;
		q.push(-s); 
	}
	//再合成其他箱子 
	while(q.size() > 1){
		long long s = 0;
		for(int i = 1;i <= m;i++){
			s+=-q.top();
			q.pop();
		}
		sum+=s;
		q.push(-s);
	}
	cout << sum;
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

T4【社恐的聚会(party)】:

1、题目大意

        有 N 个患有社交恐惧症的人想参与一个聚会,但是这个聚会只有两张桌子,这些社恐们不想跟自己不认识的人坐在一起!

        你是这次聚会的主办方,请你想想办法,看看能不能将这 N 个人分在两张桌子,使得每张桌子的任意两个人都是相互认识的。

        如果你有办法让这 N 个人分在两张桌子,请你再想想办法看看能不能让这两张桌子中人数最多的一张桌子的入座人数最少呢?

2、考试思路

        看不懂且不会,这题超纲 [我太难了],就直接判断和鸽巢原理,还真40分

3、讲解后思路

        输入 -> 把互不认识的人构成连通图 -> 二分图染色思路 -> 算最少入座人数 -> 输出

4、AC代码

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 525;
int n,tot,head[N],Next[N*N],ver[N*N],g[N][N],color[N],sz[N][2],idx;
bool vis[N],dp[N][N][2];
void add(int u,int v){
	ver[++tot] = v;
	Next[tot] = head[u];
	head[u] = tot;
}
bool dfs(int u,int c){
	//访问标记 
	vis[u] = 1;
	//u点染色为c 
	color[u] = c;
	//第 idx 个连通块人数加 1 
	sz[idx][c]++;
	for(int i = head[u];i;i = Next[i]){
		int v = ver[i];
		//已访问 
		if(vis[v]){
			//两个互不认识的人染色一致,冲突,直接不行 
			if(color[u] == color[v]){
				return 0;
			}
		}else{
			//继续深入搜索 
			if(!dfs(v,c ^ 1)){
				return 0;
			}
		}
	}
	return 1;
}
int main(){
//	freopen("party.in","r",stdin);
//	freopen("party.out","w",stdout);
	cin >> n;
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= n;j++){
			cin >> g[i][j];
		}
	}
	for(int i = 1;i < n;i++){
		for(int j = i+1;j <= n;j++){
			//把互不认识的人连一个无向边 
			if(!g[i][j] || !g[j][i]){
				add(i,j);
				add(j,i);
			}
		}
	}
	for(int i = 1;i <= n;i++){
		if(vis[i]){
			continue;
		}
		//记录连通块数量 
		idx++;
		//连通块染色 
		if(!dfs(i,0)){
			cout << "No";
			return 0;
		}
	}
	//遍历连通块
	dp[0][0][0] = 1;
	dp[0][0][1] = 1;
	int mx = n/2;
	for(int i = 1;i <= idx;i++){
		for(int j = sz[i][0];j <= mx;j++){
			dp[i][j][0] |=dp[i-1][j-sz[i][0]][0];
			dp[i][j][0] |=dp[i-1][j-sz[i][0]][1];
		}
		for(int j = sz[i][1];j <= mx;j++){
			dp[i][j][1] |=dp[i-1][j-sz[i][1]][0];
			dp[i][j][1] |=dp[i-1][j-sz[i][1]][1];
		}
	}
	int ans = 0;
	for(int j = mx;j >= 1;j--){
		if(dp[idx][j][0] || dp[idx][j][1]){
			ans = n-j;
			break;
		}
	}
	cout << "Yes" << endl << ans;
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

四、反思&总结:

       感觉这次还不错,下次尽量加快速度,多留检查时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值