文章目录
这应该是站内相对详细的解题报告吧。
转载思路请@本人。
感想
关于自己
这一次感觉还行,时间卡的比较紧,与后面几名只差了几分钟。
第一题
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有两种情况:
- 大小关系前后矛盾;
- 关系不完全,无法推出顺序。
对于第一种,我们枚举任意可重复的三个字母,然后暴力判断关系即可。
对于第二种,我们不仅要判断是否有重复关系,还要判断所有字母是否都出现。
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;
}