2021年度训练联盟热身训练赛第七场
German Collegiate Programming Contest 2020
Problem A: Adolescent Architecture
先将圆柱体的半径乘2得到直径,将所有的积木按照边长(直径)排序,从上到下遍历,如果是圆柱体,判断它上面的一个正方体的底面能否放得下(即判断圆是否大于正方形的外切圆,圆的半径应大于正方形边长的根号2倍),否则则不能搭出,输出impossible。
AC代码:
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
struct node
{
string s;
int l;
}p[105];
bool cmp(node a,node b)
{
if(a.l!=b.l)
return a.l<b.l;
else
{
if(a.s=="cylinder")
return true;
return false;
}
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>p[i].s>>p[i].l;
if(p[i].s=="cylinder")
p[i].l*=2;
}
sort(p,p+n,cmp);
int flag=1;
for(int i=1;i<n;i++)
{
if(p[i].s=="cylinder")
if(p[i].l/sqrt(2)<p[i-1].l)
{
flag=0;
break;
}
}
if(flag==0)
cout<<"impossible"<<endl;
else
{
for(int i=0;i<n;i++)
{
if(p[i].s=="cylinder")
cout<<"cylinder "<<p[i].l/2<<endl;
else
cout<<"cube "<<p[i].l<<endl;
}
}
return 0;
}
Problem F: Flip Flow
翻转沙漏,按题意模拟即可,注意考虑是翻转了奇数次还是偶数次。
AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t,s,n,l,a[1005];
cin>>t>>s>>n;
l=s;
for(int i=0;i<n;i++)
cin>>a[i];
a[n]=t;
for(int i=1;i<=n;i++)
{
if(i%2==1)
{
if(a[i]-a[i-1]<l)
l-=a[i]-a[i-1];
else
l=0;
}
else
{
if(a[i]-a[i-1]<s-l)
l+=a[i]-a[i-1];
else
l=s;
}
}
if(n%2==1)
cout<<l<<endl;
else
cout<<s-l<<endl;
return 0;
}
Problem K: Knightly Knowledge
用map分别记录纪念碑和普通教堂的横纵坐标,并记录每个普通教堂的具体位置。遍历这些横纵坐标,更新能够使得教堂升级的最大数量的值。注意如果有教堂处于两条直线交汇点,要减去重复计算的一次。
AC代码:
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int m,c,x,y;
map<int,int> monx,mony,chux,chuy;//纪念碑横纵坐标、教堂横纵坐标
map<pair<int,int>,int> chup;//教堂位置
cin>>m>>c;
for(int i=0;i<m;i++)
{
cin>>x>>y;
monx[x]++;
mony[y]++;
}
for(int i=0;i<c;i++)
{
cin>>x>>y;
if(monx[x]>1||mony[y]>1) continue;
chux[x]++;
chuy[y]++;
chup[{x,y}]=1;
}
map<int,int>::iterator it1,it2;
int ans=0,posx=0,posy=0;
for(it1=monx.begin();it1!=monx.end();it1++)
{
if(it1->second>1) continue;
for(it2=mony.begin();it2!=mony.end();it2++)
{
if(it2->second>1) continue;
int temp=chux[it1->first]+chuy[it2->first];
if(chup[{it1->first,it2->first}]==1)
temp--;
if(temp>ans)
{
ans=temp;
posx=it1->first;
posy=it2->first;
}
}
}
cout<<posx<<" "<<posy<<endl<<ans<<endl;
return 0;
}
Problem L: Lexicographical Lecturing
要求选取字符串中长度最小的一段,使其按照字典序排序与原字符串排序的结果仍保持相同。我们直接分别从头和尾开始尝试缩短字符串,时间复杂度是够的。最“暴力”的方式就可以解决了,其实也是一个贪心的思想。
AC代码:
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,l;
string s[505];
cin>>n>>l;
for(int i=0;i<n;i++)
cin>>s[i];
int left=0;
while(1)
{
int flag=1;
for(int i=1;i<n;i++)
{
if(s[i].substr(left)<=s[i-1].substr(left))
{
flag=0;
break;
}
}
if(flag==0)
{
left--;
break;
}
left++;
}
int len=l-left;
while(1)
{
int flag=1;
for(int i=1;i<n;i++)
{
if(s[i].substr(left,len)<=s[i-1].substr(left,len))
{
flag=0;
break;
}
}
if(flag==0)
{
len++;
break;
}
len--;
}
cout<<left+1<<" "<<left+len<<endl;
return 0;
}
Problem M: Mixtape Management
通过观察发现,答案要求的Windows系统下文件名排序就是按照数字大小升序排序。一种最简单的方式,我们直接将输入的每个数字输出即可。
AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,t;
cin>>n;
cin>>t;
cout<<t;
for(int i=1;i<n;i++)
{
cin>>t;
cout<<" "<<t;
}
cout<<endl;
return 0;
}