【CSDN竞赛】第十二期解题报告

18 篇文章 0 订阅
17 篇文章 0 订阅

这应该是站内相对详细的解题报告吧。
转载思路请@本人。

感想

关于自己

这一次感觉还行,时间卡的比较紧,与后面几名只差了几分钟。
第一题 i m p o s s i b l e impossible impossible没大写调了十分钟。
其他感觉还行,不像之前某场比赛都不知道怎么做(自认为对的但不通过)。
下次再接再厉。

关于平台

比赛结束后看比赛报告,结果乱码错误。现在已经修复了。
难度排序不对劲,第一题估计难倒 1 3 \frac{1}{3} 31的人。
发现跳过冷却的好方法:提交通过后直接点上面的题目来切换。
系统还是一如既往,加油。

第一题 (难度:中等+)

题目描述

已知字符 A , B , C A,B,C A,B,C。每个字符都有自己的权值q。 现不知道权值 q q q,只知道 A , B , C A,B,C A,B,C的三次比较结果。求 A , B , C A,B,C A,B,C的从小到大的顺序。

100分做法

首先,有一种很好做的方法:
记录字母间的关系,用冒泡排序来从小到大排,判断时直接用关系判断即可。
但是,判断 I m p o s s i b l e Impossible Impossible有两种情况:

  1. 大小关系前后矛盾;
  2. 关系不完全,无法推出顺序。

对于第一种,我们枚举任意可重复的三个字母,然后暴力判断关系即可。
对于第二种,我们不仅要判断是否有重复关系,还要判断所有字母是否都出现。

C + + C++ C++代码如下:

#include<bits/stdc++.h>
using namespace std;
int f[5][5]={},A[4]={0,1,2,3};//f数组记录关系
int zd[1005]={};
char dz[5]={'\0','A','B','C'};
int main()
{
	zd['A']=1;zd['B']=2;zd['C']=3;zd['<']=0;zd['>']=1;//方便存关系
	char aa,bb,cc;
	bool oka=0,okb=0,okc=0;//某个字母是否出现
	for(int i=1;i<=3;i++)
	{
		cin>>aa>>bb>>cc;
		int a=aa,b=bb,c=cc;
		oka=oka||(a=='A')||(c=='A');
		okb=okb||(a=='B')||(c=='B');
		okc=okc||(a=='C')||(c=='C');
		if(f[zd[a]][zd[c]]>0||f[zd[c]][zd[a]]>0)return 0*printf("Impossible");//判断重复
		f[zd[a]][zd[c]]=zd[b];
		f[zd[c]][zd[a]]=1-zd[b];//关系反过来
	}
	if(!(oka&&okb&&okc))return 0*printf("Impossible");//判断是否全部出现
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<=3;j++)
		{
			for(int k=1;k<=3;k++)
				if(i!=j&&j!=k&&k!=i)//判断是否矛盾,类似Floyd算法
				{
					if(f[j][k]==1&&f[j][i]==0&&f[i][k]==0)return 0*printf("Impossible");
					if(f[j][k]==0&&f[j][i]==1&&f[i][k]==1)return 0*printf("Impossible");
				}
		}
	}
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<3;j++)
		{
			if(f[A[j]][A[j+1]])swap(A[j],A[j+1]);//冒泡排序
		}
	}
	printf("%c%c%c\n",dz[A[1]],dz[A[2]],dz[A[3]]);
}

第二题 (难度:中等)

题目描述

已知一个字符串 a a a b b b。 字符串 b b b中包含数量不等的特殊符号“.”,“ * ”(字符串存在没有特殊符号或者全由特殊符号组成的情况)。 “.”表示该字符可以变成任意字符,“ * ”表示该字符的前一个字符可以变成任意多个。 现在我们想知道 b b b可否通过特殊符号变成 a a a。 a* 可以转化为a,aa,aaa,aaaa…

100分做法

d p i , j dp_{i,j} dpi,j表示 a a a匹配到 i i i b b b匹配到 j j j是否成立。
转移按照上面两种情况和直接匹配的情况转移即可。

C + + C++ C++代码如下:

#include<bits/stdc++.h>
using namespace std;
char a[10000]={},b[10000]={};
int dp[1005][1005]={};
int main()
{
	cin>>a;
	cin>>b;
	int lena=strlen(a)-1,lenb=strlen(b)-1;
	dp[0][0]=1;
	for(int i=1;i<=lena;i++)
	{
		for(int j=1;j<=lenb;j++)
		{
			if(a[i-1]==b[j-1])//直接匹配
			{
				dp[i][j]=dp[i][j]|dp[i-1][j-1];
			}
			if(b[i-1]=='.')//替代
			{
			dp[i][j]=dp[i][j]|dp[i-1][j-1];
			}
			if(i>1)
				if(b[i-1]=='*'&&b[i-2]==a[i-1])//延续
				{
				dp[i][j]=dp[i][j]|dp[i-1][j];
				}
		}
	}
	printf("%s\n",(dp[lena][lenb]==1?"yes":"no"));
	return 0;
}

第三题 (难度:简单~中等)

题目描述

小蚂蚁群是一个庞大的群体,在这个蚂蚁群中有 n n n只小蚂蚁 ,为了保证所有蚂蚁在消息传送的时候都能接收到消息,需要在他们之间建立通信关系。就是要求小蚂蚁都可以通过多只或者直接联系到其他人。 已知几条小蚂蚁之间有通信关系,请问还需要再新建至少多少条关系?

100分做法

将所有可以直接或间接联系的蚂蚁合成一个块。最后有多少个多出来的块,就要连多少条边。

C + + C++ C++代码如下:

#include<bits/stdc++.h>
using namespace std;
int fa[10005]={},qwq[10005]={};
int n,m;
int zu(int x){return (fa[x]==x?x:fa[x]=zu(fa[x]));}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(zu(x)!=zu(y))fa[zu(x)]=zu(y);//并查集
	}
	for(int i=1;i<=n;i++)qwq[zu(i)]++;//统计每只蚂蚁属于哪个块
	int tot=0;
	for(int i=1;i<=n;i++)if(qwq[i]>0)tot++;//求块数
	printf("%d\n",tot-1);//输出多余块数
	return 0;
}

第四题(难度:简单)

题目描述

已知 n n n天后的股票行情,现在已有的本金是 m m m, 规定只能入手一次股票和抛售一次股票。 最大收益(含本金)是?

100分做法

这一题送分题。求出前缀最小值和后缀最大值(先买后卖),然后对于每个位置判断即可。

C + + C++ C++代码如下:

#include<bits/stdc++.h>
using namespace std;
int MIN[10005]={},MAX[10005]={},a[10005]={};
int n,m;
int main()
{
	scanf("%d%d",&n,&m);
	MIN[0]=1e9;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		MIN[i]=min(MIN[i-1],a[i]);
	}
	int ans=0;
	for(int i=n;i>=1;i--)
	{
		MAX[i]=max(MAX[i+1],a[i]);
		int q=m/MIN[i];
		ans=max(ans,q*MAX[i]+m%MIN[i]);
	}
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值