第八届“图灵杯”NEUQ-ACM程序设计竞赛个人赛(同步赛)

第八届“图灵杯”NEUQ-ACM程序设计竞赛个人赛(同步赛)题解

第一次写题解,希望能尽快努力摆脱“小白”!
这场比赛是在放寒假不久之后在家打的第一场比赛,受个人状态以及环境影响,当然最主要的原因还是在于自身水平的不足,爆零了☹。补题的时候觉得其实至少应该可以做出四题的,嗐。

#I-买花

https://ac.nowcoder.com/acm/contest/11746/I
在这里插入图片描述
遍历K(K>1)即可,注意:输入输出

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{	
	ll a[20];
	for(ll i=1;i<=15;i++){
		a[i]=pow(2,i)-1;
	}
	ll t;
	scanf("%lld",&t);
	while(t--){
		ll n;
		scanf("%lld",&n);
		int flag=0;
		ll ans; 
		for(ll k=2;k<=15;k++){
			if(n%a[k]==0){
				flag=1;
				break;
			}
		}
		if(flag) printf("YE5\n");
		else printf("N0\n");
	} 
	return 0;
}

# D-Seek the Joker I

https://ac.nowcoder.com/acm/contest/11746/D

读懂题目之后,可以发现这道题其实就是巴什博奕的简单变形。建议把几个经典的博弈都学一下:巴什博奕、尼姆博弈、威佐夫博弈等
(由于当时还没有系统的学习过博弈的知识,感觉每一次碰到博弈问题,都有点怕怕的,然后就容易把简单问题复杂化,继续努力吧!)
巴什博奕是最后取到最后一个物品者胜利,而此题取到最后一张牌的人失败。其实也就是取到倒数第二张牌的人一定胜利,否则失败。在原巴什博奕的基础上,把牌的总数减一即可!

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t,n,k;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&k);
		if((n-1)%(k+1))printf("yo xi no forever!\n");
		else printf("ma la se mi no.1!\n");
	}
	return 0;
 } 

E-Seek the Joker II

https://ac.nowcoder.com/acm/contest/11746/E
跟D题一样为博弈论,此题为威佐夫博弈的变形
(当你对各种博弈都很熟悉清晰的时候,自然会很容易联想到的)
此题乌龟上方的x-1张牌即为第一堆物品,乌龟下方的n-x张牌即为第二堆物品。抽中乌龟的失败将上述两堆物品先抽完的胜利,否则失败。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{	
	int t;
	cin>>t;
	while(t--){
		int n,x;
		cin>>n>>x;
		int a=min(x-1,n-x);
		int b=max(x-1,n-x);
		int c=b-a;
		double r=(sqrt(5.0)+1)/2;
		if(a==(int)(c*r)) printf("ma la se mi no.1!\n");
		else printf("yo xi no forever!\n");
	}
	return 0;
}

F-成绩查询ing

https://ac.nowcoder.com/acm/contest/11746/F
一看这种题,立马想到用结构体,结果就T了o(╥﹏╥)o
所以一定要注意数据范围啊!
两种查询操作:1)输入同学姓名,输出该同学的成绩、学号和性别。姓名和成绩、学号、性别一一对应,但用结构体暴力查会T。于是用map(key与value一一对应)
2)输入成绩,输出考到此成绩的同学姓名,按字典序输出。因为要排序,所以用set最合适不过了,set自动去重并排序。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	int n;
	cin>>n;
	set<string> s[120];
	map<string,int>mp1;
	map<string,int>mp2;
	map<string,int>mp3;
	for(int i=1;i<=n;i++)
	{
		string Name;
		int xb,xh,cj;
		cin>>Name>>cj>>xb>>xh;
		s[cj].insert(Name);
		mp1[Name]=cj;
		mp2[Name]=xh;
		mp3[Name]=xb;
	}
	int m;
	cin>>m;
	while(m--){
		int q;
		cin>>q;
		if(q==1){
			string t;
			cin>>t;
			cout<<mp1[t]<<" "<<mp2[t]<<" "<<mp3[t]<<endl;
		}
		else{
			int k;
			cin>>k;
			set<string>::iterator it;
			it=s[k].begin();
			for(;it!=s[k].end();it++){
				cout<<*it<<endl;
			}
		}
	}
	return 0;
}

C-上进的凡凡

https://ac.nowcoder.com/acm/contest/11746/C
求给定数组的非降序子数组的个数。
我们知道一个非降序数组的所有子数组均为非降序(其实所给样例也在给我们提示),且长度为n的数组的子数组个数为n(n+1)/2
将给定数组分成若干个非降序的数组(长度尽可能的长),并将每个非降序数组的子数组个数相加即可。
(数据范围大,暴力求解会T)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int a[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	ll ans=0;
	ll t=0;
	for(int i=1;i<=n;i++){
		if(a[i]>a[i+1]||i==n){
            t=i-t;//非降序数组的长度
			ans+=(t*(t+1))/2;
			t=i;
		} 
	}
	printf("%lld\n",ans);
    return 0;
}


B-小宝的幸运数组

https://ac.nowcoder.com/acm/contest/11746/B
若给定数组某一子数组的总和能整除K,则该子数组即为幸运子数组,现求最长的幸运子数组的长度。
求某一子数组的总和:利用前缀和
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
#define inf 0x3f3f3f3f
typedef long long ll;
ll a[maxn];//记录前缀和取余结果 
int l[maxn],r[maxn];//记录各余数出现的最小位置及最大位置 
int num[maxn];//记录各余数的个数 
int main()
{
	int t,n,k;
	scanf("%d",&t);
	while(t--){
		memset(a,0,sizeof(a));
		memset(r,0,sizeof(r));
		memset(num,0,sizeof(num));
		for(int i=0;i<maxn;i++) l[i]=inf;
		scanf("%d%d",&n,&k);
		int flag=0;
		l[0]=0;
        num[0]=1;//余数为0时
		for(int i=1;i<=n;i++){
			ll x;
			scanf("%lld",&x);
			a[i]=(a[i-1]+x)%k;
			l[a[i]]=min(l[a[i]],i);
			r[a[i]]=max(r[a[i]],i);
			num[a[i]]++;
			if(num[a[i]]>=2) flag=1; //相同余数至少要有两个
		}
		if(!flag) printf("-1\n");
		else{
			int ans=0;
			for(int i=0;i<maxn;i++){
				if(num[i]>=2){
					ans=max(ans,r[i]-l[i]);
				}
			}
			printf("%d\n",ans);
		}
	}
    return 0;
}

H-数羊

https://ac.nowcoder.com/acm/contest/11746/H
m只能取0、1、2;因此将三种情况都计算出来就好啦
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
#define inf 0x3f3f3f3f
typedef long long ll;
const int mod=998244353;
ll speed(ll a,ll b){//快速幂!!!
	ll ans=1;
	while(b){
		if(b&1) ans=(ans*a)%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans%mod;
}
int main()
{
	ll t,n,m;
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld",&n,&m);
		ll ans;
		if(m==0){
			ans=n+2;
		}
		else if(m==1){
			ans=2*n;
		}
		else{
			ans=speed(2,n);
		}
		printf("%lld\n",ans%mod);
	}
    return 0;
}

K-黑洞密码

https://ac.nowcoder.com/acm/contest/11746/K
注意读题,审清题意。
输入长度为32的仅有字母和数字组成的字符串。将其分为字母和数字两部分,每部分长度均为16,且两部分相同位置上的字母与数字一一对应。又将每部分分为四组,每组四个,依据转化规则转换后,颠倒顺序输出。
特别注意:‘z’之后是’B’,‘Z’之后是’b’;

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
#define inf 0x3f3f3f3f
typedef long long ll;
int main()
{
	string s;
	cin>>s;
	vector<char>a[4];//存放四组字母
	vector<int>b[4];//存放四组数字
	int ca=0,cb=0,cnt1=0,cnt2=0;
	for(int i=0;i<s.length();i++){
		if(isalpha(s[i])){
			ca++;
			a[cnt1].push_back(s[i]);
			if(ca%4==0) cnt1++;
		}
		else{
			cb++;
			b[cnt2].push_back(s[i]-'0');
			if(cb%4==0) cnt2++;
		}
	}
	int j;
	for(int i=0;i<4;i++){
		string ans;
		for(int j=0;j<4;j++){
			for(int k=0;k<b[i][j];k++){
				if(a[i][j]=='Z') a[i][j]='b';//'Z'之后是'b'
				else if(a[i][j]=='z') a[i][j]='B';//'z'之后是'B'
				else a[i][j]=(char)(a[i][j]+1);
			}
			ans+=a[i][j];
		}
		reverse(ans.begin(),ans.end());//颠倒顺序
		cout<<ans; 
	}
	cout<<endl;
    return 0;
}

J-这是一道简单的模拟

https://ac.nowcoder.com/acm/contest/11746/J
题如其名,这真的是一道简单的模拟!
数据范围很小,用二维数组存图即可。但需注意几点:
1)相邻城市存在通路;
2)恰好能都到达N个出差城市一次(不能漏掉!也不能重复!)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
#define inf 0x3f3f3f3f
int a[maxn][maxn];
int vis[maxn];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<=n;i++){
		for(int j=0;j<=n;j++){
			a[i][j]=inf;
			a[j][i]=inf;
		}
	}
	while(m--){
		int u,v,w;
		cin>>u>>v>>w;
		a[u][v]=w;
		a[v][u]=w;
	}
	int k;
	cin>>k;
	int ans=inf;
	while(k--){
		int n;
		cin>>n;
		int x=0,y;
		int flag=0,flag1=0;
		int sum=0;
        memset(vis,0,sizeof(vis));
		for(int i=0;i<n;i++){
			cin>>y;
            vis[y]++;
			if(a[x][y]!=inf){//相邻城市存在通路
				sum+=a[x][y];
			}
			else{
				flag=1;
			}
            x=y;
		}
		if(a[y][0]!=inf) sum+=a[y][0];
        else flag=1;
        for(int i=1;i<=n;i++){
            if(vis[i]!=1){//每个城市恰好到达一次
                flag1=1;
                break;
            }
        }
		if(!flag&&!flag1) ans=min(ans,sum);
	}
	if(ans!=inf) cout<<ans<<endl;
	else cout<<"-1\n";
    return 0;
}

L-建立火车站

求最大值的最小值:二分搜答案
这个知识点我还不是特别理解,通过看别人的题解,懂了那么一点点,还需要做一些这方面的题,以加深我的理解、加强运用能力。
最终答案范围确定:所有城市坐标小于等于10^12,且不存在负值

#include<bits/stdc++.h> 
using namespace std; 
const int MAXN=100005; 
long long a[MAXN];
int n,k;
long long judge(long long mid){
	int m=0;
	for(int i=2;i<=n;i++) 
		if(a[i]-a[i-1]>=mid){//两城市之间的距离大于等于mid时,才能在两城市之间建立临时停靠站
		m+=(a[i]-a[i-1])/mid;//临时停靠站距离为mid时,在两城市之间能建立的停靠站个数
		if((a[i]-a[i-1])%mid==0) m--;//若距离为两城市间距离的整数倍,则第一个临时停靠站的位置与原城市位置重复,需减一
	}
	if(m>k) return 0;//若此时能建立的停靠站的数量大于k,说明距离还太小了,需继续增大距离mid,故调整l
	return 1;
}
int main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i]; 
	sort(a+1,a+1+n);
	long long l=0;
	long long r=1000000000000; 
	while(l<r){
	long long mid=(l+r)/2; 
	if(judge(mid)==1)
		r=mid;
	else
		l=mid+1;
	}
	cout<<l<<endl; 
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值