今晚参加了CodeM2018初赛A,结果只做对了两题……
第1题:求一段字符串对应手机按键移动最少次数。
送分题非常简单,我的解法是一个数组保存A-Z的按键,一个二维数组保存按键之间的距离。读入字符串只需要记住当前的和它的前一个字母,查表加和。排行榜上的大佬们2-5分钟就写完提交,但我实在没那么快。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main(){
int i,j,k,n,T,f,sum;
int latterMap[26]={1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,6,7,7,7,8,8,8,8};
int distMap[9][9]=
{{0,1,2,1,2,3,2,3,4},
{1,0,1,2,1,2,3,2,3},
{2,1,0,3,2,1,4,3,2},
{1,2,3,0,1,2,1,2,3},
{2,1,2,1,0,1,2,1,2},
{3,2,1,2,1,0,3,2,1},
{2,3,4,1,2,3,0,1,2},
{3,2,3,2,1,2,1,0,1},
{4,3,2,3,2,1,2,1,0}};
char c,c0,xx[3];
scanf("%d",&T);gets(xx);
for(k=0;k<T;k++){
f=0;sum=0;
while(scanf("%c",&c)==1 && c!='\n'){
printf("c=%c\n",c);
if(f==0){
sum+=distMap[0][latterMap[c-'A']];
f=1;
}else sum+=distMap[latterMap[c0-'A']][latterMap[c-'A']];
c0=c;
}
printf("%d\n",sum);
}
return 0;
}
第2题: 一个1*n的棋盘上,每个格子放着一些棋子,每个棋子可以向左移,或者向左移动到最左边以后再向右移,给出棋子总数相同的状态A和B,求状态转换需要移动的次数。
这个题本来设想的是从左到右扫描,把第一个状态的棋子挨个转换为第二个状态,移动次数相加。但是提交不对,就去玩了半个时,时间浪的差不多了回来再看,然后发现了这样不对:
应该先从右向左遍历第一个状态的所有棋子,把其中能够只通过左移就能达到第二状态的棋子先减去,然后再从左向右次数相加,再注意数据大小就能通过。
可能这样设想的比较麻烦,大佬们应该有更简便的做法。另外在自己电脑VS根本开不了这么大数组,都是小数组编好,在提交时候再把数组改大。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int min(int a,int b){
return a<b?a:b;
}
int main(){
int i,j,k,n,f;
long long ans=0;
int a[100010],b[100010],num,done,x;
scanf("%d",&n);
if(n==1){printf("0\n");return 0;}
memset(a,0,sizeof(a));b[0]=0;
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)scanf("%d",&b[i]);
i=n;j=n;
while(i>0 && j>0){
while(a[i]==0 && i>0)i--;
while(b[j]==0 && j>0)j--;
while(i<j && j>0)j--;
if(i>=j){
if(a[i]>=b[j]){
ans=ans+b[j]*(long long)(i-j);
a[i]=a[i]-b[j];
b[j]=0;
j--;
}
if(a[i]<=b[j]){
ans=ans+a[i]*(long long)(i-j);
b[j]=b[j]-a[i];
a[i]=0;
i--;
}
}
}
for(i=1;i<=n;i++)a[i]=a[i-1]+a[i];
j=1;done=0;
for(i=1;i<=n;i++){
num=b[i];
b[i]=b[i-1]+b[i];
if(num!=0){
while(b[i]>=a[j] && j<=n){
if(i<=j){
x=min(b[i]-done,(a[j]-done));
ans=ans+x*(long long)(j-i);
done=done+x;
}
else if(i>j){
x=min(b[i]-done,(a[j]-done));
ans=ans+x*(long long)(j+i-2);
done=done+x;
}
j++;
}
if(j<=n && b[i]>a[j-1] && b[i]<a[j]){
if(i<=j){
x=min(b[i]-done,(a[j]-done));
ans=ans+x*(long long)(j-i);
done=done+x;
}else if(i>j){
x=min(b[i]-done,(a[j]-done));
ans=ans+x*(long long)(j+i-2);
done=done+x;
}
}
}
}
printf("%lld\n",ans);
return 0;
}
后面题目没来得及看了,最终排名前600,只有前250名才能进复赛,又看了一下去年初赛B轮比A轮难一些,估计复赛无望了(望天)