1001 随机序列
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
题目描述
国中生Chino总是做不完数学作业,Cocoa想来帮忙,但作业太多了,怎么也做不完。
Chino的数学作业由T(1≤T≤100)T(1\leq T\leq 100)T(1≤T≤100)张试卷组成,每张试卷上有n(1≤n≤103)n(1\leq n\leq 10^3)n(1≤n≤103)个数a1..n(1≤a≤5000)a_{1..n}(1\leq a\leq 5000)a1..n(1≤a≤5000),Chino需要算出这些数的极差和方差。极差是一个整数,方差是一个浮点数,要求保留到小数点后3位。
虽然题目很简单,但计算量对于Chino来说实在太大啦!你能帮一帮她吗?
P.S.:一个数列的极差是指数列中最大的数减去最小的数,方差是指算出数列中每个数与数列平均值之差的平方后,对其求和,再除以数列元素个数得到的结果。
输入描述:
输入的第一行有一个数T,表示试卷的数量;接下来的每2行,第一行有一个数n,表示当前试卷上数字的个数;第二行有n个数字aia_iai,表示这张试卷上的每一个数。
输出描述:
对每张试卷,输出一行两个数,分别表示这些数字的极差和方差,中间用空格分开。其中极差是整数,方差是保留到小数点后3位的浮点数。
代码:
#include<stdio.h>
#include<math.h>
int main()
{
int t,n,a[5000];
int i=0,j,jicha,max,min,sum;
double fangcha,aver;
scanf("%d",&t);
for(i=0;i<t;i++)
{
scanf("%d",&n);
sum=0;
fangcha=0;
jicha=0;
//以上三个变量每次循环前记得归零
for(j=0;j<n;j++)
{
scanf("%d",&a[j]);
sum+=a[j];
}
max=min=a[0];
aver=1.0/n*sum;
for(j=0;j<n;j++)
{
if(a[j]>max) max=a[j];
if(a[j]<min) min=a[j];
fangcha+=pow(a[j]-aver,2);//方差
}
jicha=max-min;//极差
printf("%d %.3f\n",jicha,fangcha/n);
}
return 0;
}
思路:
利用输入和循环的配合,来保证输入数据个数正确。每次循环后输出当前的结果,之后进行下一轮循环中的输入。
思路:
1002 [NOIP2013]记数问题
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
题目描述
试计算在区间1 到n 的所有整数中,数字x(0 ≤ x ≤ 9)共出现了多少次?
例如,在1到11 中,即在1、2、3、4、5、6、7、8、9、10、11 中,数字1 出现了4 次。
输入描述:
输入共1行,包含2个整数n、x,之间用一个空格隔开。
输出描述:
输出共1行,包含一个整数,表示x出现的次数。
代码:
#include <stdio.h>
int main ()
{
int i,j,a,t=0,n;
scanf("%d %d",&n,&a);
for(i=1;i<=n;i++)
//一个循环,依次判断当前数字i,是否是指定数字a
{
for(j=i;j;j/=10)
//判断条件为j,当j被除至商为0时停止
//此时刚好判断完i所有位数是否含指定数字a
{
if(j%10==a)
t++;
}
}
printf("%d",t);
return 0;
}
思路:
1. 当前代码思路:
思路较为简单,从1到n依次判断每个数中含有几个a,累加起来。
2. 刚开始的个人思路:
起初感觉一个一个循环,判断,计数太过耗时,于是为避免一个一个数去判断和计数,尝试用分析规律,直接计算的方式来编,降低时间复杂度。分析n的每一位上的数与指定数字a的大小关系,直接计算从1到n的n个数中,个位、十位、百位...出现a的次数——结果编不出来,测试用例连一半都没过,自己实在分析不出来,于是我屈服了,屈服给了嵌套循环。
后续:用这个思路ac了,运行时间也降下来了!
代码:
#include <stdio.h>
int main ()
{
int i,j,a,ans=0,n;
scanf("%d %d",&n,&a);
for(i=1;n/i;i*=10)
{
if(a==0)
//a==0情况特殊单独讨论
{
if(n/i<10) break;
//a==0时,最大位上的数不能参与计算
//且最高位不可能为0
if((n/i)%10>a)
//当 当前位上的数 大于a(也就是0)时
//同一般情况下的 ((n/i)%10<a)
//因为是从1开始的计数,而不是从0开始的
//所以才是和 ((n/i)%10<a)情况相同
//而不是 ((n/i)%10>a)的情况
ans+=(n/i/10)*i;
/*
以255为例
个位是0的情况:10 20 ...
100(只会计算个位的0的个数,所以不必担心十位上的0是否会漏掉)
... 200 ... 250 共25个
符合表达式:n/10
十位是0的情况:100 101 102 ... 109 200 201 ... 209 共20个
符合表达式:n/100*10
测试多组类似数据后,
于是可以发现规律:(n/i/10)*i;
*/
else
//当 当前位上的数 等于a(也就是0)时
//此情况与一般情况的 当前位的数【(n/i)%10==a】不一样
ans+=n-(n/i*i-1)+((n/i-1)/10)*i;
/*
以207为例
个位是0:10 20 ... 200 共20个
不够特殊,下一位
十位是0:100 101 ... 109 200 201 ... 207 共18位
很明显不可以与【a==0&&(n/i)%10>a】的情况共用同一表达式
所以才有对本情况的讨论
经过多组数据的测试
最终才得出一个表达式:
n-(n/i*i-1)+((n/i-1)/10)*i
(其实这个表达式的具体意义我也不算很清楚,毕竟是试出来的)
*/
}
else
//一般情况的讨论与分析过程类似a==0的情况,不再一一赘述了(其实是讲不清)
{
if((n/i)%10<a)
ans+=(n/i/10)*i;
else if((n/i)%10>a)
ans+=(n/i/10+1)*i;
else ans+=n-(n/i*i-1)+(n/i/10)*i;
}
}
printf("%d",ans);
return 0;
}
运行时间直接降到个位数!!! 嘴角疯狂上扬!
咳咳,毕竟第一次,多少得意一点应该没事吧(小声)
本代码通过和原本已经ac的(思路1的)代码进行对比,分析各种情况的输入下的输出差异,来进行调试,毕竟题目公布出来的测试用例只有一组,很难分析代码为什么没有通过,自己是漏掉了哪种情况。
自己列测试用例要考虑的情况:
- 一般情况(a!=0)
- 某一位上的数大于指定数a