输出
对每组输入数据,输出a^b的最后一位数字,每组数据占一行。
样例输入
22
34
样例输出
4
1
思路/方法:
如果你模拟a^b次肯定会超时,而且数字还会超出Int范围
题目说只要最后一个数字,回想一下小学时学的乘法过程,貌似乘数最后一位和前面的无关
我们大胆的尝试一下用a的个位代替a,然后我们发现循环b次还是会超时,这是我们要想办法减少循环的次数,试一下是不是有周期规律
这时我们来列举一下2的n次方的个位:
24862486
我们发现周期为4,我们在试试1-9的n次方,发现周期都是4,所以,我们可以用b%4代替b,需要注意的是,当b%4==0时,我们需要给他加上4,不然就不循环了。
代码:
#include
intmain()
{
inta,b,i,t;
while(scanf("%d%d",&a,&b)!
=EOF)
{
b=b%4;
if(b==0)
b=4;
a=a%10;
t=1;
for(i=0;i
{
t=t*a;
t=t%10;
}
printf("%d\n",t);
}
return0;
}
3:
筛选法求素数
描述
请使用筛选法输出[a,b]之间的所有素数。
输入
输入数据有多组,每组数据占一行,每行2个正整数a和b,其中2<=a<=b<=1000000。
输出
每组数据按从小到大的顺序输出[a,b]中所有的素数,每行最多输出10个素数。
每组数据之后空一行。
样例输入
23
250
样例输出
23
2357111317192329
3137414347
思路/方法:
这题测试的数据量很大,所以尽量少循环,尽量少判断,要非常精简才能通过。
1.定义一个全局变量shorts[1000001];//全局变量默认为0
2.把数组中下标为奇数的值改为1,偶数不用改,因为除了2,其他偶数都不是素数
s[2]=1;//2也是素数
for(i=3;i<1000001;i=i+2)//把奇数全部假设为素数
s[i]=1;
3.把素数的倍数挖掉,改为0。
(从2开始到根号1000000之间的素数的倍数挖掉)
for(i=2;i<1000;i++)//小于根号1000000
if(s[i])//判断是否为素数,只有素数的倍数才挖掉
for(j=i*2;j<1000001;j=j+i)//把i的倍数的值改成0
s[j]=0;
4.最后一点是输出格式,每组之间一个空行,另外一行最多10个。
定义一个变量来记录输出了多少个,达到十个就输出换行。
具体看代码。
代码:
#include
shorts[1000001];//全局变量默认为0
intmain()
{
intt,a,b,i,j;
s[2]=1;//2也是素数
for(i=3;i<1000001;i=i+2)//把奇数全部假设为素数
s[i]=1;
for(i=2;i<1000;i++)//小于根号1000000
if(s[i])
for(j=i*2;j<1000001;j=j+i)//把i的倍数的值改成0
s[j]=0;
while(scanf("%d%d",&a,&b)!
=EOF)
{
t=0;
for(i=a;i<=b;i++)
{
if(s[i])//素数就输出
{
if(t)
if(t==10)
{
printf("\n");
t=0;
}
else
printf("");
t++;
printf("%d",i);
}
}
printf("\n\n");
}
return0;
}
4:
Theonestoremain
描述
ThereareNsoldiersstandinginoneline.Theyaremarkedfrom1toN,fromrighttoleft.Andtheyaregivenanumberm.Thenthesoldiersnumberedoff,straightfromtheright-handman.Theonewhoreportedanumberthatisthemultipleofmwaskeptintheline.Othershavetoleavetheline.Theycontinuedoingthistillthenumberofpeopleinthelineislessthanm.Forexample,ifthereare10soldiers,andm=3.Forthefirsttimethesoldierswhoaremarked3,6,9remainintheline.Forthesecondtimethesoldierwhoismarked9remainsintheline.Becausethenumberofsoldiersinthelineislessthanm,sothesoldiermarked9wastheonlyonetoremainintheline.
Nowwewanttoknowwhowillbetheonestoremain,canyoutellus?
输入
Thereareseveraltestcasesintheinput.Eachtestcasesisonlyoneline,containstwointegersnandm.(3<=n<=109,2<=m<=n).Theinputendswhenn=0andm=0.
输出
Foreachtestcase,outputtwolines.Thefirstlinecontainsoneintegerx,thenumberofsoldierstoremain.Thesecondlinecontainsxintegers,thenumbersmarkedonthesoldierswhoremainintheline.Youshouldoutputtheminincreasingorder.
样例输入
103
83
00
样例输出
1
9
2
36
翻译:
描述
有N个士兵站在一行。
他们被从右到左标记为1到N。
他们被给与了一个数字m。
然后士兵直接从右面报数。
报的数是m的倍数的留下来,其他人离开。
然后继续上述操作,直到人数少于m。
例如,有10个士兵,m=3。
第一次士兵报数为369的留下,第二次士兵报数为9的留下。
输入
有多组测试数据。
每组一行两个数nm(3<=n<=109,2<=m<=n),以00结束
输出
每组输出两行,第一行输出一个x表示留下来的士兵数量,第二行输出x个留下来的士兵的编号。
思路/方法:
这题用数组来存储士兵状态就会超时,所以我们需要更精简的算法,很明显可以看出这是道数学题,所以我们多举几个例子,看看是否有规律。
m=2时
12
2
123
2
1234
24
4
123456
246
4
12345678
2468
48
8
m=3时
123
3
1234
3
123456
36
123456789
369
9
由上面的几个例子可以看出关键是找到一个不大于n的最大的m^x。
比如m=2的时候,依次是2^12^12^22^22^3,当x一样时,他们的结果值一样,并且就是m^x。
当m=3时,依次是3^13^13^13^2,不难发现,x一样时,结果的第一个数一样是m^x。
接下来要找出有多少个结果值,比较m=3时的前3组数据,发现第三组第二个结果6是3*2且不大于n=6,我们大胆推断m的个数就是不大于n的3的倍数的个数。
然后我们继续举个例子检验一下推论。
123456789101112
4812
如上,当m=4时,只有m^1不大于n,所以结果第一个数为4,然后后面有812为4的倍数,且不大于n,所以得到3个结果,和例子的结果一致。
这样就成功推出了解题方法,虽然不严谨,但作为一般人,能做出来就行了。
代码:
#include
usingnamespacestd;
intmain()
{
longlongm,n,remain,id,j;//id表示下标,j表示当前第几个报数
while(cin>>n>>m,!
(n==0&&m==0))
{
//得到不大于n的m^x的值
j=1;
for(id=1;;id++)
{
j=j*m;
if(j*m>n)
break;
}
remain=0;
for(id=1;;id++)
{
if(j*id<=n)//得到不大于n的m的倍数的个数
remain++;
else
break;
}
cout<for(id=1;idcout<cout<}
return0;
}
5:
小数化分数
描述
Ray在数学课上听老师说,任何小数都能表示成分数的形式,他开始了化了起来,很快他就完成了,但他又想到一个问题,如何把一个循环小数化成分数呢?
请你写一个程序不但可以将普通小数化成最简分数,也可以把循环小数化成最简分数。
输入
第一行是一个整数N,表示有多少组数据。
每组数据只有一个纯小数,也就是整数部分为0。
小数的位数不超过9位,循环部分用()括起来。
输出
对每一个对应的小数化成最简分数后输出,占一行。
样例输入
3
0.(4)
0.5
0.32(692307)
样例输出
4/9
1/2
17/52
思路/方法:
这题需要有个数学转化方法,小编看了别人的纯循环小数转分数的方法,然后又花了点时间推出了非纯循环小数转分数方法,下面分享一下。
1.有限小数:
分子分母乘以10的次方,使得没有小数位,然后分子分母分别除以最大公约数就化简完成。
比如0.4,就是0.4*10/10,最大公约数为2,化简后就是2/5
2.纯循环小数
乘以10的次方使得循环部分没有小数位,然后用该数-原数=整数部分。
所以分数形式=循环节/9...9(9的个数等于循环节数字个数)
例如:
0.44..,0.444..*10-0.444..=4。
所以(10-1)*0.44..=4。
0.44..=4/9。
3.非纯循环小数
乘以10的次方使得循环部分没有小数位记为a*10^x,乘以10的次方使得非循环部分没有小数记为a*10^y,则a*10^x-a*10^y就消去了后面的小数。
比如:
0.2433..*1000-0.243..*100=243-24,所以0.243..=(243-23)/(1000-100),然后总结之后得出下面的结论。
不循环部分和循环节构成的的数减去不循环部分的差,再除以循环节位数个9,添上不循环部分的位数个0。
比如:
0.24333333…………=(243-24)/900=73/300
0.9545454…………=(954-9)/990=945/990=21/22
方法有了,代码也容易写,但小编做的时候犯了一个错误,把循环部分和非循环部分全都当成整数来接受,导致丢失了位数,使得分母不准确了。
比如0.001(02)这样的,当成整数接受,非循环部分是1,算长度的时候直接算就是1,循环部分接受后变成2,算长度是1,导致分母变成了90,而实际上是99000。
所以必须用字符串来存储,具体看代码了。
代码:
#include
#include
longlonggreatestCommonDivisor(longlonga,longlongb)
{
longlongt;
while(b)
{
t=a%b;
a=b;
b=t;
}
returna;
}
intmain()
{
inti,n,j,k;
longlongdenominator,numerator,divisor,cyclical,nonCyclical;//分母分子,非循环部分和循环部分
chara[20],nonCyclicalString[20],cyclicalString[20];//必须用文本,否则会丢失位数,比如0.001010这样的会把0丢了
scanf("%d",&n);
for(i=0;i{
scanf("0.%s",a);
getchar();
if(strchr(a,'(')!
=NULL)//有循环小数的情况
{
if(a[0]=='(')//如果是纯循环小数
{
sscanf(a,"(%s",cyclicalString);//只能这样读取,把括号补充完整也一样的结果
cyclicalString[strlen(cyclicalString)-1]='\0';//手动删除后面的括号。
读取到了循环部分
sscanf(cyclicalString,"%I64d",&cyclical);
nonCyclicalString[0]='\0';
numerator=cyclical;//分子就等于循环节
}
else
{
for(j=0;a[j]!
='(';j++)//读取到(就停止。
读取非循环部分
nonCyclicalString[j]=a[j];
nonCyclicalString[j]='\0';
for(k=0,j=j+1;a[j]!
=')';j++,k++)//从(右边一个开始读取到)就停止。
读取循环部分
cyclicalString[k]=a[j];
cyclicalString[k]='\0';
sscanf(nonCyclicalString,"%I64d",&nonCyclical);//把非循环部分的值放入到变量中
sscanf(cyclicalString,"%I64d",&cyclical);//把循环部分的值放入到变量中
numerator=nonCyclical;//把分子的值先变成非循环部分
for(j=0;cyclicalString[j]!
='\0';j++)//往分子尾部加入循环节部分
{
numerator=numerator*10+(cyclicalString[j]-'0');
}
numerator=numerator-nonCyclical;//非循环部分和循环部分的组合-非循环部分
}
//计算分母
denominator=0;
for(j=0;cyclicalString[j]!
='\0';j++)//加上循环节个数个9
denominator=denominator*10+9;
for(j=0;nonCyclicalString[j]!
='\0';j++)//加上非循环部分个0
denominator=denominator*10;
divisor=greatestCommonDivisor(numerator,denominator);
printf("%I64d/%I64d\n",numerator/divisor,denominator/divisor);
}
else//非循环小数
{
sscanf(a,"%I64d",&numerator);//把小数部分存到变量中
denominator=1;
for(j=0;a[j]!
='\0';j++)//计算分母
denominator=denominator*10;
divisor=greatestCommonDivisor(numerator,denominator);
printf("%I64d/%I64d\n",numerator/divisor,denominator/divisor);
}
}
return0;
}
6:
全排列
描述
任意输入n个不重复的整数序列,输出序列的全排列。
输入
测试数据有多组,第一行是整数t(0每组测试数据有两行,第一行是整数的个数n(0输出
按递增的顺序输出序列的全排列。
每个测试数据后面输出一个空行。
样例输入
1
3
135
样例输出
135
153
315
351
513
531
思路/方法:
全排列有递归和非递归算法,具体网上有,这里我们为了代码简洁,采用STL里面的函数来实现,容易理解,而且好写。
首先引用algorithm这个库,然后里面有sort排序函数和next_permutation下一个排列函数。
sort升序排序,参数分别是首地址和末地址
next_permutation是判断是否有下一个排列,有返回true,并且改变数组状态,否则返回false。
参数分别是首地址和末地址
代码:
#include
#include
usingnamespacestd;
voiddisplay(inta[],intn)
{
inti