上竞赛课以来第一次考试,谜之运气爆棚。
总之因为犯了一些死蠢的错误,来写个考试分析。
第一题
货物互通(goods)
【题目描述】 在银河系中有好多有着高等生物的类地球星球,α星球和β星球就是其中的两个,这两个星球每年都
会派出大使互通货物,α大使和β大使会先带着货物都到达位于中间的γ星球交换货物,如果α大使带的 货物更值钱,β大使需要再付相差的β币,如果β大使带的货物更值钱的话,α大使需要再付相差的α币。 请帮助α大使和β大使计算出,需要付的相差的币值,如果货物等价则输出 0。
【输入】 输入三行,第一行有两个整数:α星球的货币进制 A和β星球的货币进制 B(2 <= A,B <= 16) 第二行为α大使所带货物的价值(α进制数) 第三行为β大使所带货物的价值(β进制数)
【输出】 输出为一行,需要付给对方的相差(α或β)币值。
【数据范围】 对于 100%数据,2 <= A,B <= 16,αβ星球的货物价值不超过 10 进制 long long 范围。
总之看完题就知道,这是一道会让人写的十分闹心的进制转换。
大概需要注意的点有以下几个
1.因为有十进制以上的进制,所以要注意字符与数字之间的转换
这一项我预处理了两个数组c2n和n2c。
2.注意数据范围是不超过十进制的long long范围,那么转换成最长的 或者说是二进制数 最多会有64位,所以存数的时候至少要开一个长度为64的数组
我差点就被这儿坑了……一开始写的数组大小只有40,还是我后来写完了随便给自己出了一组数据发现数组越界才发现的=-=|||果然数据范围最坑人【明明是你不仔细看题
3.如果是a的货物比b多的话,多付的钱用b进制表示,反之用a进制表示。
第一次写的时候就写反了……输入样例发现咋有那么多f,才知道写错了orz
我的代码如下
#include<stdio.h>
#include<string.h>
long long b10=0,a10=0;
char aho[70];
char bho[70];
int ans[70];
int c2n[255];
char n2c[255];
long long quana[65];
long long quanb[65];
int zhuan(int k,long long x)
{
int cnt = 0;
do
{
ans[cnt]= x%k;
x = x/k;
cnt++;
}while(x>0);
return cnt;
}
int main()
{
for(int i = 'A';i<= 'F';i++)
{
c2n[i] = i-'A'+10;
n2c[i-'A'+10] = i;
}
for(int i ='0';i<='9';i++)
{
c2n[i] = i-'0';
n2c[i-'0'] = i;
}
int a,b;
scanf("%d%d",&a,&b);
quana[0]=1;
quanb[0]=1;
for(int i = 1;i<=64;i++)
{
quana[i]=quana[i-1]*a;
quanb[i]=quanb[i-1]*b;
}
scanf("%s",aho);
scanf("%s",bho);
for(int i = 0;i<strlen(aho);i++)
{
a10+=c2n[aho[i]]*quana[strlen(aho)-1-i];
}
for(int i = 0;i<strlen(bho);i++)
{
b10+=c2n[bho[i]]*quanb[strlen(bho)-1-i];
}
if(a10==b10)
{
printf("0");
}
else if(a10>b10)
{
int cnt = zhuan(b,a10-b10);
for(int i = cnt-1;i>=0;i--)
{
printf("%c",n2c[ans[i]]);
}
}else if(a10<b10)
{
int cnt = zhuan(a,b10-a10);
for(int i = cnt-1;i>=0;i--)
{
printf("%c",n2c[ans[i]]);
}
}
return 0;
}
现在看来真是一坨莫名其妙的代码…尤其是看了标程之后【手动打脸表情
第二题
【题目描述】 交易完成后α大使准备返回α星球的时候,发现飞船有故障,每当仪 表里程盘里面的数字更新时,如果里面包含数字 x,飞船就会颠簸,里面有 几个 x 就会颠簸几下,出发前仪表盘的里程数是 S,到α星球的距离是 L, 请帮忙求出整个返回过程中,到达α星球时,飞船一共会颠簸多少下。
【输入】 输入为一行,三个整数,依次是初始里程数 S,距离 L,会产生颠簸的数字 x。
【输出】 输出为一行一个整数,飞船总共颠簸的次数。
数位分割求某个数字出现的次数,很简单的题,老师还贴心的给出了样例解释,于是我绕过了唯一一个坑。
坑:数字是从开始变化的开始颠,初始数值不算,所以循环其实是从初始里程值+1开始的。
于是我的代码如下
#include<stdio.h>
int dian;
int judge(int x)
{
int cnt = 0;
do
{
if(x%10==dian)
{
cnt++;
}
x/=10;
}while(x>0);
return cnt;
}
int main()
{
int start,length,ans = 0;
scanf("%d%d%d",&start,&length,&dian);
for(int i = start+1;i<= start+length;i++)
{
ans+=judge(i);
}
printf("%d",ans);
return 0;
}
这里要说一下,函数里写do while是因为本来没注意到那个坑,以为可能从0开始……
后来发现了坑,于是不可能从0开始了……但也懒得改了……毕竟这么写也没啥错【摊手
第三题
【题目描述】 α大使历尽颠簸千辛,终于回到了α星球,正好赶上了α星球最盛大的节日:电话节。α星球共有 N 户人家,每户人家都有一个威望值 ai,在电话节的时候,每户人家都要给其他所有人打电话,通话时间就 是两家威望的乘积,请帮忙算一下,一个电话节下来,α星球总共会产生多少通话时间,答案可能会很大, 最终答案 mod 10009 即可。
【输入】 第一行一个数字 N,表示α星球共有 N 户人家。 第二行有 N 个整数,表示α星球每户人家的威望 ai。
【输出】 输出一个整数,最终答案 mod 10009 的结果。
【样例解释】 a1和 a2通话时间是 6, a1和 a3通话时间是 8, a2和 a1通话时间是 6, a2和a3通话时间是12, a3和 a1通话时间是 8, a3和a2通话时间是12, 总通话时间为 6 + 8 + 6 + 12 + 8 + 12 = 52。
依旧是良心样例解释系列……我一开始根本没懂样例为啥得52……
经过分析后可知,第ai家要给除ai的其他所有人打电话,于是ai家的通话时间就为
ai = ai*a1+ai*a2*………………+ai*an;
于是整理得ai= ai*(a1+a2+……a(i-1)+a(i+1)……+an)
同时可预先将a1~an加和为sum
则ai = ai*(sum-ai);
这道题最神的是我一开始莫名算错数据范围用了个快速乘……于是时间复杂度升高……但这还不是重点 重点是我当场居然踩着线拿了满点orz
当然后来测就是最后两个点超时了……不过把快速乘去掉之后就好了……
考试的时候一定是有幸运之神附体了orz
这道题需要注意的还有要在过程中一直mod10009,不然也会瞬间爆炸【X
总之去掉了快速乘的代码如下……
#include<stdio.h>
int mod = 10009;
int weiwang[1000005];
int main()
{
long long sum = 0;
int n;
scanf("%d",&n);
for(int i = 1;i<= n;i++)
{
scanf("%d",&weiwang[i]);
sum +=weiwang[i];
}
long long ans = 0;
for(int i = 1;i<= n;i++)
{
ans=(ans+weiwang[i]*(sum-weiwang[i]))%mod;
}
printf("%I64d",ans);
return 0;
}
以上……就是竞赛课开始之后的第一次考试