这是我第一次在比赛过程中写出来三道题,毕竟这次的题目比较简单……
A题是一道最大公约数的模板题。Ciel有n个不同的正整数,x1,x2,……xn,她可以做任意次如下操作:从中选择两个不同的序数i和j,使得xi>xj然后做运算xi=xi-xj,目标是使这个数组的和尽可能小。
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int i,a[110],min,tag,n;
while(cin>>n)
{
min=110;
for(i=0;i<n;i++)
{
cin>>a[i];
if(a[i]<min)
min=a[i];
}
tag=0;
while(tag==0)
{
tag=1;
for(i=0;i<n;i++)
{
if(a[i]%min)
{
tag=0;
min=a[i]%min;
}
}
}
cout<<n*min<<endl;
}
}
B题是一道简单的暴力。在一个图中有n*n个格子,每个格子中包含一个标记"."或者一个标记“#”,在图中的一个交叉就是从图中找到五个格子,使他们形成一个十字型。Ciel想在格子上边画十字,每个十字必须包含五个"#",两个十字不能包含同一个格子。求是否能够将所有的“#”字给覆盖住。
这道题提交的时候有一次在geta函数里面用的是getchar(),不知道为什么总是不对。改成cin就正确了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int map[105][105];
int visit[105][105];
int geta(){
char a;
cin>>a;
while(a!='#'&&a!='.'){
cin>>a;
}
if(a=='#')return 1;
else return 0;
}
int main(){
// freopen("data.txt","r",stdin);
ios::sync_with_stdio(false);
int n;
memset(visit,0,sizeof(visit));
cin>>n;
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
char a;
int t=geta();
map[i][j]=t;
}
}
if(map[0][0]||map[0][n-1]||map[n-1][0]||map[n-1][n-1]){
cout<<"NO"<<endl;
return 0;
}
// for(int i=0;i<n;++i){
// for(int t=0;t<n;++t){
// cout<<map[i][t]<<' ';
// }
// cout<<endl;
// }
for(int i=1;i<n-1;++i){
for(int j=1;j<n-1;++j){
if(map[i][j]&&!visit[i][j]){
if((map[i-1][j]&&!visit[i-1][j])&&map[i][j-1]&&map[i+1][j]&&map[i][j+1]&&!visit[i][j-1]&&!visit[i+1][j]&&!visit[i][j+1]){
visit[i-1][j]=1;
visit[i][j-1]=1;
visit[i+1][j]=1;
visit[i][j+1]=1;
visit[i][j]=1;
}
}//if
}//for j
}//for i
// for(int i=0;i<n;++i){
// for(int t=0;t<n;++t){
// cout<<visit[i][t]<<' ';
// }
// cout<<endl;
// }
bool can=1;
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
if(map[i][j]&&!visit[i][j]){
// cout<<i<<' '<<j<<endl;
can=0;break;
return 0;
}
}
}
if(can)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
C题给出了一堆箱子,第i个箱子最多只能在它上面放xi个箱子。要求出最少把这些箱子放成几摞可以把箱子码起来。
模拟就可以
#include<iostream>
#include<algorithm>
using namespace std;
int x[105];
int visit[105];
int main(){
// freopen("data.txt","r",stdin);
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=0;i<n;++i){
cin>>x[i];
}
sort(x,x+n);
int sum=n;
int tot=0;
while(sum){
int pile=0;
for(int i=0;i<n;++i){
if(visit[i])continue;
if(x[i]>=pile&&!visit[i]){pile++;visit[i]=1;}
}
sum-=pile;
tot++;
}
cout<<tot<<endl;
return 0;
}
这三道题就是比赛过程中写出来的题目。倒数第二题看了一遍题目感觉不会,然后看最后一题。当时感觉挺会的,然后花了十分钟把代码写出来,过了pretest,拿到了200多名……这是我拿到的最好的名词。但是当时就感觉最后一道题要么错了要么超时。第二天所有数据测完果然错了……当时的思路就是每次找到最顶上最大的一个拿出来,然后找到最底部最大的一个拿出来。但是这样的方法是错误的。
就比如说有这样一组数据
3 1 3 2
3 5 4 6
2 8 7
如果按照这样的方法来取得话,答案是18 26,不过如果第一个人先拿2,然后紧接着把8给拿到手,这样第一个人的得数就会大一些,即第一个人拿2,8,3,5,3,1第二个人拿7,6,4,2,3这样答案就是22,22。
在两个人拿牌的过程中,假设其中有一个牌比较大,那么两个人都会想办法去抢这张牌。其结果就是如果这张牌在上边部分,那么第一个人就会拿到这张牌,如果这张牌在下半部分,那么第二个人就会拿到这张牌。所以,最终结果一定是上半部分的牌全部归第一个人,下半部分的牌全部归第二个人。如果一打牌的数量是基数,那么中间一张牌特殊处理就可以了。
#include<iostream>
#include<algorithm>
using namespace std;
int cards[105][105];
int rec[105];
int main(){
ios::sync_with_stdio(false);
// freopen("data.txt","r",stdin);
int n;
cin>>n;
int s=0;
int Csum=0;
int tot=0;
for(int i=0;i<n;++i){
int tmp;
cin>>tmp;
for(int t=0;t<tmp;++t){
cin>>cards[i][t];
tot+=cards[i][t];
}
for(int t=0;t<tmp/2;++t){
Csum+=cards[i][t];
}
if(tmp%2){
rec[s++]=cards[i][tmp/2];
}
}
sort(rec,rec+s);
for(int i=s-1;i>=0;i-=2){
Csum+=rec[i];
}
cout<<Csum<<' '<<tot-Csum<<endl;
return 0;
}