2021四川省赛A,B,D,H,K

2021 年第十三届四川省 ACM-ICPC 大学生程序设计竞赛(重现赛)

2021四川省赛题场链接


A.Chuanpai

题目链接

签到题没啥好说的。代码如下:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
	int t,n;
	cin>>t;
	while(t--)
	{
		cin>>n;
		int l=n/2;
		int sum =0;
		for(int i =1;i<=l;i++)
		{
			if(i<=6&&n-i>=1&&n-i<=6) sum++;
		} 
		cout<<sum<<endl;
	}
	return 0;
} 

B.Hotpot

题目链接

题目大意:
t组样例,每组n个人吃火锅,有k种食材,所有人总共可以操作m次,然后告诉你每个人最喜欢的食材是哪个。至于怎么操作呢,那就是轮到哪个人,那个幸运儿就去看看锅里面有没有他爱吃的,有的话他就吃掉并且快乐值++;没有的话他就会往里面加这种食材,没得吃也不能增加快乐值。

解题思路:
讲个笑话,打比赛的时候我没注意数据范围,用暴力WA了两次,补题的时候又各种细节上的小错误不断,又WA了七次(别骂了别骂了)。

好了说正经的。首先,看数据范围,不能暴力。那就得看看有没有什么规律可循。初步思考可以发现,如果有两个人,都喜欢吃食材1,那么第一个人放进去第二个人吃,那么第一个人快乐值永远为0(因为他一直在放,没得吃),第二个人的快乐值就是m/2(m次操作两个人轮流)。但是如果人数为奇数的情况下,比如有三个人,都喜欢食材1,总共能操作20次,那么在第一轮操作时,第一个人和第三个人是吃不到的,第二个人可以吃到,但是轮到第二轮时,第一个人和第三个人是能吃到的,但是第二个人吃不到。那么我们就可以将两轮看做一个循环,20/6=3,只要记录第一次循环每个人的快乐值再*3,20%6=2;暴力解决剩下两次,就OK啦。

#include<iostream>
#include<cstring>
using namespace std;
const int N=1e5+10;
struct f{
    int x;//每个人喜欢的食物
    int happy;//每个人的快乐值
}a[N];
int v[N];//用来记录锅子里有没有这个食材
long long n,k,m;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(v,0,sizeof(v));
        cin>>n>>k>>m;
        for(int i=0;i<n;i++){
        	cin>>a[i].x;
        	a[i].happy=0;
		}
        if(m>=2*n)
		{
	        for(int i=0;i<2*n;i++)
	        {
	            int j=i%n;
	            if(v[a[j].x]==0){//锅子里没有喜欢的食材
	            	v[a[j].x]++;//放进食材
				}else{//锅子里有喜欢的食材
	                v[a[j].x]--;//吃掉
	                a[j].happy++;//他快乐了
	            }
	        }
	        for(int i=0;i<n;i++)
	        	a[i].happy*=(m/(2*n));//以2*n为一次循环,有几次循环就让快乐值乘几
        }
        for(int i=0;i<m%(2*n);i++)//剩下的操作次数
        {
            int j=i%n;
            if(v[a[j].x]==0)v[a[j].x]++;
            else
            {
                v[a[j].x]--;
                a[j].happy++;
            }
        }
        for(int i=0;i<n;i++)
        {
            if(i)cout<<" ";
            cout<<a[i].happy;
        }
        cout<<endl;
    }
    return 0;
}

D.Rock Paper Scissors

题目链接

题目大意:
玩石头剪刀布的游戏,t组样例,每组两行分别代表两个人拥有的牌,赢的人得一分,输的人扣一分,打平不得分,要求出第二行那个人运气最最好的情况下得几分。

解题思路:
如果让第二个人出石头,那就要让第一个人出剪刀,如果让第二个人出剪刀,就要让第一个人出布,如果让第二个人出布,那就让第一个人出石头,这样就能让第二个人的得分达到最大,因此先尽量多的用这种方法达到分数最大。如果剩下还有牌的话,尽量选择打平手,这样至少不扣分。最后如果还剩下牌的话,那就只剩下“输”这一种情况了,那就只能扣分了。

代码如下:

#include<iostream>
using namespace std;
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		long long sum=0;
		long long a[3];
		long long b[3];
		cin>>a[0]>>a[1]>>a[2];
		cin>>b[2]>>b[0]>>b[1];
		//当时这么写输入是为了后面写赢的情况的时候能方便一点
		//但是事实上并不会方便多少,后面另外两种情况还是得换回来
		for(long long i=0;i<3;i++)//赢的情况
		{
			if(b[i]>=a[i]){
				sum+=a[i];
				b[i]-=a[i];
				a[i]=0;
			}else{
				sum+=b[i];
				a[i]-=b[i];
				b[i]=0;
			}
		}
		
		long long x=b[2];b[2]=b[1];b[1]=b[0];b[0]=x;
		for(long long i=0;i<3;i++){//打平的情况
			if(b[i]>=a[i]){
				b[i]-=a[i];
				a[i]=0;
			}else{
				a[i]-=b[i];
				b[i]=0;
			}
		}
		
		for(long long i=0;i<3;i++)//输的情况
		{
			sum-=b[i];
		}
		cout<<sum<<endl;
	}
	return 0;
}

H.Nihongo wa Muzukashii D

题目链接

(别看题目链接了,直接看我写的题目大意吧。相信我,题目没什么好看的。)

题目大意:
t组样例,每组给你一个单词。如果这个单词的后缀是“imasu”“chimasu”“rimasu”,那就替换成“tte”;如果后缀是“mimasu”“bimasu”“nimasu”,那就替换成“nde”;如果后缀是“kimasu”,那就替换成“ite”,但是如果这个单词是“ikimasu”那就另当别论——直接输出“itte”即可;如果后缀是“gimasu”,那就替换成“ide”;如果后缀是“shimasu”,那就替换成“shite”。

解题思路:
请先允许本英语菜鸟吐槽一下,当时看这个题目差点给我看吐了,但是看完之后才意识到,这真的是一道再简单不过的字符串题目。

通过题目我们不难发现,它们的后缀都是“masu”,那么我们其实只要比对masu”前面的几个字符就可以了。做法很简单,分类讨论,多写几个if就好了。但是要注意一下,先比对字符串比较长的(比如说“shimasu”)。如果把字符短的写在前面的话,会判断错,比如说先比对“imasu”,那如果输入的其实是“mimasu”也会先被判为“imasu”。还有就是如果碰到“ikimasu”是直接输出“itte”而不是把后缀替换成“itte”,我一开始就因为这个原因WA了一发。所以这个最好写在最前面特判。

代码如下:

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		char a[35];
		cin>>a;
		int len=strlen(a);
		if(strcmp(a,"ikimasu")==0) cout<<"itte"<<endl;
		else{
			if(a[len-7]=='c'&&a[len-6]=='h'&&a[len-5]=='i'){
				a[len-7]='\0';
				cout<<a<<"tte"<<endl;
			}else if(a[len-7]=='s'&&a[len-6]=='h'&&a[len-5]=='i'){
				a[len-7]='\0';
				cout<<a<<"shite"<<endl;
			}else if(a[len-6]=='r'&&a[len-5]=='i'){
				a[len-6]='\0';
				cout<<a<<"tte"<<endl;
			}else if(a[len-6]=='m'&&a[len-5]=='i'){
				a[len-6]='\0';
				cout<<a<<"nde"<<endl;
			}else if(a[len-6]=='b'&&a[len-5]=='i'){
				a[len-6]='\0';
				cout<<a<<"nde"<<endl;
			}else if(a[len-6]=='n'&&a[len-5]=='i'){
				a[len-6]='\0';
				cout<<a<<"nde"<<endl;
			}else if(a[len-6]=='k'&&a[len-5]=='i'){
				a[len-6]='\0';
				cout<<a<<"ite"<<endl;
			}else if(a[len-6]=='g'&&a[len-5]=='i'){
				a[len-6]='\0';
				cout<<a<<"ide"<<endl;
			}else if(a[len-5]=='i'){
				a[len-5]='\0';
				cout<<a<<"tte"<<endl;
			}
		}
		
	} 
	return 0;
 } 

K.K-skip Permutation

题目链接

题目大意:
给你P个数,从1到P的每个数都要用到,你要使这些数字尽量排成一个序列,使后面那个数比前面那个数字大k。然后你要尽量使这些序列多。

解题思路:
一开始我理解错了题意(英语菜鸟吃大亏),WA了一次。我想的方法是用两个for循环,外层是每个序列的头,内层就接着外层的数不断的增加k直到超过P的大小。设一个变量num,每增加一次就num++,num达到P的时候就说明每个都被用过了。

#include<iostream>
using namespace std;
int main()
{
	int P,k;
	cin>>P>>k;
	int num=0;
	for (int i=1;i<=P;i++)
    {
        for (int j=0;j*k+i<=P;j++)
        {
            num++;
            if (num<P) cout<<j*k+i<<" ";
            else cout<<j*k+i;
        }
        if(num==P) break;
    }
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值