2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)

A-A+B Problem_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

A-A+B Problem

题解:

该题只要找到最大的数,只要将其他数和最大的数相加即可,但是最大的数需要和第二大的数相加;所以我们可以用优先队列储存数组,在用一个普通数组储存输入,枚举数组中的元素,如果枚举到其中一个元素等与优先队列的队头,那么我们就将队头弹出,将新队头+现在的元素,然后再把弹出的队头在加入其中;

#include<bits/stdc++.h>
using namespace std;
int b[200005];
int main(){
	int n;
	cin>>n;
		priority_queue<int,vector<int>>a;
	for(int i=1;i<=n;i++){
		
		cin>>b[i];
		a.push(b[i]);
	}
		for(int i=1;i<=n;i++){
			if(a.top()!=b[i]){
				cout<<b[i]+a.top()<<" ";
			}
			else {
				int y=a.top();
				a.pop();
				cout<<b[i]+a.top()<<" ";
				a.push(y);
			}
		}
		return 0;
}

 B-Komorebi的数学课_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

B-Komorebi

题解:我们举一个例子:n=7时;

7 7 7 7 7 7 7;

此时有7个一相乘;

那么我们两个两个合并;

就变成了:

49 49 49 7;

由此当长度为计数的时候我们用p来储存他多出来的数字;

那么n就变成了49,此时长度从7也变成了3(7/2);

p=7;

现在我们将49合并,此时就变成了2401(49*49);

还剩下一个49,将他存入p中,p就变成了7*49;

现在只剩下一个长度为1的2401;

结束循环,此时将2401*p%(n+2);

当长度大于一时,我们就两两合并相同的元素,如果长度为1,那么必定会有一个元素单出来。

那么我们就把单出来的元素放入p中,最后将长度为一的时候就乘以p;

当然快速幂能更快的解决,我这个好像就是快速幂的思想:

#include<bits/stdc++.h>
using namespace std;
int b[1005];
#define int long long
signed main(){
	int n;
	cin>>n;
	int p=1;
	int mod=n+2;
	int len=n;
	while(len!=1){
		int m=(n*n)%mod;
		if(len%2==0){
			len/=2;
		}
		else{
			p*=n;
			len/=2;
			p%=mod;
		}
		n=m;
		
	}
	cout<<(n*p+mod)%mod<<endl;
	return 0;
}

 C-次佛锅_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

 C-次佛锅

map的用法,以及字符串的处理,自己模拟

#include<bits/stdc++.h>
using namespace std;
map<string,int>a;
signed main(){
	string s;
	string str;
	string ne;
	int f=0;
	getline(cin,s);
	for(int i=0;i<s.size();i++){
		if(s[i]==' '){
			f++;
			if(f%2==0){
				int n=stoi(ne);
				a[str]+=n;
			}
			else {
				str=ne;
			}
			ne.clear();
		}
		else {
			ne+=s[i];
		}
		if(i==s.size()-1){
			int n=stoi(ne);
			a[str]+=n;
		}
		
	}
		int t;
		cin>>t;
		while(t--){
			string k;
			cin>>k;
			cout<<a[k]<<endl;
		}
		return 0;
	
}

D-Setsuna的K数列_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

 D-Setsuna的K数组

读题:二进制的感觉,此时我们就不是以2为底数了,而是以k为底数,我们先将n转换成二进制;

然后要是二进制的某一位为1,那么加上以k为底的x次幂;即可;

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int a[2000006];
signed main(){
	int n,k;
	cin>>n>>k;
		int i,j=0;
		i=n;
		while(i)
		{
			a[j]=i%2;
			i/=2;
			j++;
		}
		int ans=0;
		int x=1;
		for(i=0;i<=j-1;i++){
			if(a[i]==1)ans+=x;
          ans%=mod;
			x*=k;
           x%=mod;
			
		}
		
		cout<<(ans+mod)%mod<<endl;;
	

}

F-黄金律法_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

 F-黄金律法:

此题只用将a数组中的最大值乘以b数组的最小值即可;

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[100005];
int b[100005];
signed main(){
	int t;
	cin>>t;	
	int n;
	while(t--){
	
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		for(int j=1;j<=n;j++){
			cin>>b[j];
		}
		sort(a+1,a+1+n);
		sort(b+1,b+1+n);
		int ans=0;
		for(int i=1;i<=n;i++){
			ans+=a[i]*b[n-i+1];
		}
		cout<<ans<<endl;
	}
	
	return 0;
	
}

J-史东薇尔城_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

 J-史东薇尔城

堆优化的Dijkstra算法,因为要从某一点到起点1,然后从1点到另一点,所以最后的答案输出就是

dist[x]+dist[y];

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
vector<PII>mp[150005];
int n,m;
int dist[150001];
bool st[155001];
void djstl(){
	for (int i = 1; i <=n ; ++i) {//举例数组初始化为无穷大
		dist[i]=(int)1e15;
	}
	priority_queue<PII,vector<PII>,greater<PII>>q;//定义优先队列
	dist[1]=0;//起点的距离是0
	q.push({0,1});//将起点放入队列中,要对距离排序,所以距离在第一位
	while(!q.empty()){//如果队列不为空
		auto t=q.top();//将距离最小的点弹出
		q.pop();
		int ver=t.second,ds=t.first;//最上面的点标号是ver,距离是ds;
		if(st[ver])continue;//如果该点已经确定了最短路,就继续找下一个最近的点
		st[ver]= true;//标记
		for (int i = 0; i <mp[ver].size() ; ++i){//找以ver为出边所连接的点
			auto p=mp[ver][i];//枚举所有他所连接的点;
			if(dist[p.first]>ds+p.second){//如果1到该点的距离大于(已经确定最短路的点到该点的距离加上最短路的距离)
				dist[p.first]=ds+p.second;//更新该点的最短距离
				q.push({dist[p.first],p.first});//将已经找到最短路的点放入队列中;
			}
		}
	}
}
signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for (int i = 0; i <m ; ++i) {
		int x,y,z;
		cin>>x>>y>>z;
		mp[x].push_back({y,z});//读入边
		mp[y].push_back({x,z});
	}
	djstl();//进行最短路
	int t;
	cin>>t;
	while(t--){
		int a,b;
		cin>>a>>b;
		cout<<dist[a]+dist[b]<<endl;
	}
	return 0;
	
}

L-剪绳子_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

 L-剪绳子

暴力枚举就行,将剪断过的数存入在set里面,让他自动排序,然后每次要求输出数就遍历set知道找到set中的某个元素大于输入的f元素,不然一直更新他的左端点,否则更新右端点f,然后break;

输出两者的差值即可;

#include<bits/stdc++.h>
using namespace std;
#define int long long
set<double>ans;
signed main(){
	int t;
	cin>>t;
	while(t--){
		string a;
		cin>>a;
		double f;
		cin>>f;
		if(a=="C"){
			ans.insert(f);
		}
		else {
			double start=0.0;
			double endd=10.0;
			for(auto p:ans){
				if(p>f){
					endd=p;
					break;
				}
				start=p;
			}
				printf("%.5f\n",endd-start);
		}

	}
	return 0;
}

H-叠硬币_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com

 H-叠硬币

01背包,动态规划;

dp[i]中储存的是高度为i的最小堆数是多少;

01背包的思路:

当他可以装 j 体积的东西时,也就是当高度为j时,比较高度为j-a[i]时在加上本省自己的堆数时,谁的堆数最小;

最后输出答案时,因为要求输出字典序最小,所以我们就从数组i开始枚举,如果要求的减去目前这堆的高度后的堆数等于答案的堆数减一,就说明你是其中一个答案,输出就行,那么要求的高度就要更新为减去这堆高度的高度;因为h是根据前面的高度堆数累加上来的。所以一定存在,如果当堆数满足要求时,后面就一定存在与该堆数匹配最后高度为h的堆数;

说的要点乱,看代码注释吧;

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int arr[N];
int dp[N];
int main(){
	int n,h;
	cin>>n>>h;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	sort(arr+1,arr+1+n);//对数组从小到大排序
	memset(dp,0x3f,sizeof dp);//求最小值 赋值最大
	dp[0]=0;//边界条件
	for(int i=1;i<=n;i++){
		for(int j=h;j>=arr[i];j--){//滚动数组中的第二层循环要从大到小,防止他更新的是i,
			//实质上他更新的是i-1;
			dp[j]=min(dp[j],dp[j-arr[i]]+1);//高度为h的最小堆数
			//体积为arr[i],权重为他的堆数——1堆
		}
	}
	//如果高度为h,且他没有被更新过
	if(dp[h]==0x3f3f3f3f)cout<<"-1\n";
	else {
		cout<<dp[h]<<"\n";//最少有几堆
		int p=dp[h];
		p--;
		for(int i=1;i<=n;i++){//枚举数组中的堆数
			if(dp[h-arr[i]]==p){//高度减去(某一堆)的高度剩下的堆数最少有几堆;
				cout<<arr[i]<<" ";//输出该数组
				h-=arr[i];//将高度减去这一堆的高度
				p--;//堆数减减
			}
		}
	}
	
	
	return 0;
}

 G-天气预报_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

 G-天气预报:

用两个指针:

对于一个01字符串,要找到有几个区间满足0数量和1的数量分别不小于a和b

它是有单调性:当右边界满足的时候,后面的也一定满足,所以答案直接加上n-左边界,剩下的右边界就都是答案。
故可以双指针来维护,需要注意的是 a==0 b==0 这种情况,还需额外加1。因为题目说了可以啥都不选

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a,b,sum;
int l,r;
int x,y;
int q,p;
signed main()
{
	cin>>n>>a>>b;
	string s;
	cin>>s;
	int ans=0;
	for(int i=0,j=0;i<s.size();i++)
	{
		if(s[i]=='1')y++;
		else x++;
		while(x>=a&&y>=b&&j<=i)
		{
			ans+=n-i;
			if(s[j]=='0')x--;
			else y--;
			j++;
		}
	}
	if(a+b==0)cout<<ans+1;
	
	else cout<<ans;
		return 0;
}

E-Wiki下象棋_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

E—Wiki下象棋:

E-Wiki下象棋_2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(重现赛)@IR101 (nowcoder.com)

第一个bfs1是国际象棋的做法,第二个bfs2是中国国旗的做法

国际象棋的走法是:
每一步只可以水平或垂直移动一点,再按对角线方面向左或者右移动(另一种解释,可以先在水平/竖直方向走两格,然后在竖直/水平方向走一格)。另外,马不允许跳出界外,也即必须跳完一步之后仍在棋盘上。

中国象棋的走法:
在没有障碍物的情况下,其走法与国际象棋一样。唯一不同的是,如果马走了一格就遇到障碍物,马就不能继续向这个方向前进了(又称为"马脚")。

题目中,国际象棋是没有障碍物的;

所以可以直接按照马走的日字格宽度优先搜索;

中国象棋中有马脚,所以在每一次走日字格的时候要判断所谓的马脚是否存在;

如果存在就跳过这个日,循环找别的日字;

#include<bits/stdc++.h>
using namespace std;
const int N=300+9,M=N*N+9;
int mp[N][N];
int n,m,k,a,b,c,d;
int ans1,ans2;
int vis[N][N];
struct node {
    int x,y,step;
};
int dx[]={-1,-2,-2,-1,1,2,2,1};
int dy[]={-2,-1,1,2,2,1,-1,-2};
int bfs1(){
    queue<node>q;
    while(q.size())q.pop();
    q.push({a,b,0});
    vis[a][b]=1;
    if(a==c&&b==d)return 0;
    while(q.size()){
        auto p=q.front();
        q.pop();
        for(int i=0;i<8;i++){
            int nx=dx[i]+p.x,ny=dy[i]+p.y;
            if(nx<1||nx>n||ny<1||ny>m)continue;
            if(vis[nx][ny])continue;
            if(mp[nx][ny]==-1)continue;
            vis[nx][ny]=1;
            if(nx==c&&ny==d){
                return p.step+1;
            }
            q.push({nx,ny,p.step+1});
        }
    }
    return -1;
}
int nox[]={0,-1,-1,0,0,1,1,0};
int noy[]={-1,0,0,1,1,0,0,-1};
int bfs2(){
    queue<node>q;
    while(q.size())q.pop();
    q.push({a,b,0});
    vis[a][b]=1;
    if(a==c&&b==d)return 0;
    while(q.size()){
        auto p=q.front();
        q.pop();
        for(int i=0;i<8;i++){
            int nx=dx[i]+p.x,ny=dy[i]+p.y;
            int nnx=p.x+nox[i],nny=p.y+noy[i];
            if(nx<1||nx>n||ny<1||ny>m)continue;
            if(mp[nx][ny]==-1)continue;
            if(mp[nnx][nny]==-1)continue;
            if(vis[nx][ny])continue;
            vis[nx][ny]=1;
            if(nx==c&&ny==d){
                return p.step+1;
            }
            q.push({nx,ny,p.step+1});
        }
    }
    return -1;
}
int main(){
    std::ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        memset(vis,0,sizeof vis);
        ans1=ans2=0;
        cin>>n>>m>>k>>a>>b>>c>>d;
        memset(mp,0,sizeof mp);//!!
        while(k--){
            int x,y;
            cin>>x>>y;
            mp[x][y]=-1;
        }
        // cout<<"---"<<endl;
        cout<<bfs1()<<" ";
        memset(vis,0,sizeof vis);
        cout<< bfs2()<<"\n";
    }
    return 0;
}

“夏天一闪而过

还好我们常常见面  \( ̄︶ ̄)/”

  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值