1.小鱼比可爱
洛谷P1428
单目鱼只会向左看,那就让每个鱼都去看一看它前面鱼是否比它可爱,用计数器计数即可
需要注意的是每条鱼计数完后需要将计数器重置为0
#include <stdio.h>
int main(){
int n,i,j,count=0;
scanf("%d",&n);
int a[n];//若是使用标准c可以使用malloc为其分配内存
for(i=0;i<n;i++){//外层循环给每一条鱼向左看的机会
scanf("%d",&a[i]);
for(j=0;j<i;j++){//内层循环让每条鱼都能扫视它前面所有的鱼
if(a[i]>a[j]){
count++;
}
}
printf("%d ",count);
count=0;
}
}
return 0;
}
2.素数回文数的个数
洛谷B2136
此题突破两点即可,一是素数,二是回文数
素数:除了1和它本身没有别的因子☞遍历2到该数前一个数(提高效率可以只遍历到其平方根)作为除数,挨个判断即可
回文数:正着看和倒着看一样☞直接求其反过来的值与原值对比即可
#include<stdio.h>
#include<math.h>
int judge1 (int a)//判断素数
{
int i;
if(a%2==0)return 0;//提高效率
for(i=2;i<sqrt(a);i++){
if(a%i==0){
return 0;
}
}
return 1;}
int judge2(int a)//判断回文数
{
int r=0,temp=a;
while(a){
r=r*10+a%10;
a/=10;
}
if(r==temp){
return 1;
}
else return 0;
}
int main ()
{
int a=0,n;
scanf("%d",&n);
for(int i=11;i<=n;i++){
if(judge(i)&&judge2(i)){
a++;
}
}
printf("%d\n",a);
return 0;
}
3.开关灯
洛谷B2092
开和关是两种状态,正巧二进制也只有0和1两个数,所以很自然地就能联想到当将开设为1,关设为0的操作
#include <stdio.h>
int main(){
int n,i,j,k;
scanf("%d",&n);
int a[n];
for(i=0;i<n;i++){
a[i]=0;
}//第一个人将灯全部关闭
for(i=1;i<n;i+=2){
a[i]=1;
}//第二个人将灯全部打开
for(i=3;i<=n;i++){//控制第n个人
for(j=i-1;j<n;j+=i){//让第n个人去其倍数的灯做相反操作
if(a[j]==1)a[j]=0;
else a[j]=1;
}
}
for(k=0;k<n;k++){
if(a[k]==0)printf("%d ",k+1);
}//灯和数组里的存储差了1,需要需要加1
return 0;
}
4.确定进制
洛谷B2141
-
先确定大体思路:将需要测试的进制全部从小到大遍历一遍,如果过程中找到第一个使条件成立的就退出循环,如果遍历完了仍然没能退出循环,就说明不存在符合的进制输出
0
好处:可以直接找到最小的进制,不用作比较
-
遍历过程需要注意的一点:需要测试的进制不一定都要从
2
开始,需要确定三个数最小能存在的进制举个例子:
31,5,96
☞进制只能从10
开始遍历,因为10
以下的进制不存在9
这个数的表达 -
将
10
进制转化为b
进制,即将其n位分别*b
的n-1
次方 -
在转化的过程中可能会出现数值过大导致无法过所有测试点的情况,所以通篇采用了long long int的定义
#include <stdio.h>
long long int zhuanhua(long long int n,long long int b){
long long int sum=0;
long long int i,j=0;
while(n>0){
long long int m=n%10;//每轮分离出每次的个位
n/=10;
for(i=1;i<=j;i++){
m*=b;
}//该步也可以用math.h库中的pow函数替代
sum+=m;
j++;
}
return sum;
}//将10进制数转化为b进制数
long long int judge(long long int p,long long int q,long long int r,long long int b){
if(p>=b)p=zhuanhua(p,b);
if(q>=b)q=zhuanhua(q,b);
if(r>=b)r=zhuanhua(r,b);
if(p*q==r)return 1;
else return 0;
}//将p,q,r转化后判断其是否满足表达式
long long int maxn(long long int i){
long long int p=i;
long long int max=0;
for(long long int j=0;p>0;j++){
i=p%10;
p/=10;
if(i>max)max=i;
}
return max;
}//找一个数各位最大的数
int main(){
long long int p,q,r;
long long int i;
scanf("%lld %lld %lld",&p,&q,&r);
long long int max;
long long int a=maxn(p),maxn=n(q),maxn=n(r);
if(a>=b&&a>=c)max=a;
if(b>=a&&b>=c)max=b;
if(c>=a&&c>=b)max=c;
//此处找到三个数各位最大的数
for(i=max+1;i<=16;i++){
if(judge(p,q,r,i)){
printf("%lld",i);
break;
}
if(i==16)printf("0");//遍历完了都没找到,即不存在
}
return 0;
}
5.拼数
洛谷P1012
-
初版思路的实现与更新:
直接将各个数以整型去比较会很麻烦,如果是以字符串去比较则很简单,
strcmp
函数完美地满足了题目的需求,但是需要结合循环不断地比较,实际实现起来又会陷入新的麻烦所以采用
qsort
函数,用qsort
去直接对字符串进行比较并排序,将对应的cmd
函数用strcmp
改造即可 -
读取数据时的问题:
如果直接读入字符串也会很麻烦,因为各个数据输入在一行,而
scanf(%s)
和gets
等等都会直接读取完一行,所以先以整型读入,再用sprintf
函数将其转化为字符串 -
各个函数的作用:
sprintf
将""
内读入的内容以字符串的形式读进数组(数组名,格式化控制字符,需要读入的具体内容)strcmp
接受两个字符串,从左往右进行两个字符串的各个字符比较,直接遇到不一样的为止(串1,串2)qsort
将对应的比较函数进行改造,可以比较各种类型的数据(要排序的数组,需要排序的元素个数,一个元素的大小,比较函数),详细介绍请查阅其他资料
于是初版代码得以实现:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cmd(const void* a,const void* b){
return strcmp((char*)b,(char*)a);
}
int main(){
int n;
scanf("%d",&n);
char str[n][10];
int a[n];
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
sprintf(str[i],"%d",a[i]);
}
int t=sizeof(str)/sizeof(str[0]);
qsort(str,t,sizeof(str[0]),cmd);
for(int i=0;i<n;i++){
printf("%s",str[i]);
}
return 0;
}
但是交上去只有75分,说明大体思路没问题
查看测试点会发现一个很巧妙的点,将32
和321
进行排序的时候,按照上面排序的逻辑排下来是32132
,但这显然没有32321
大,所以需要进一步改变比较的逻辑
既然不能只看单个字符串间的比较,那直接将它们拼接后的结果进行比较就好了,问题得以解决,修改代码如下
补充下面的两个字符串函数注解:
strcpy
接受两个字符串,将第一个字符串清除,随后第二个字符串到第一个字符串上(串1,串2)strcat
接受两个字符串,将第二个字符串接到第一个字符串上(串1,串2)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cmd(const void* a, const void* b) {
char ma[20], mb[20];
strcpy(ma, (char*)a);
strcpy(mb, (char*)b);
char *m = strcat(ma, mb);
char *n = strcat(mb, ma);
return strcmp(n,m);
}
int main(){
int n;
scanf("%d",&n);
char str[n][10];
//用二维数组来储存多个字符串
int a[n];
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
sprintf(str[i],"%d",a[i]);
//sprintf函数可以将“”内的内容以字符串的形式储存到str中
}
int t=sizeof(str)/sizeof(str[0]);
qsort(str,t,sizeof(str[0]),cmd);
//按首字符大小进行排序
for(int i=0;i<n;i++){
printf("%s",str[i]);
}
return 0;
}
6.高精度减法
洛谷P2142
- 为什么要用高精度以及第一步:存:
我们知道,当数的范围超过了long long int
就会爆掉,这时就需要请出我们的高精度,本题正是如此
整型存放不下,就只能用数组去存了,而在读入时如果读到整型数组里面又会爆掉,不得不用字符串数组了
当然毕竟是数的运算,所以字符串数组接受后还是需要转化为整型存入数组的,字符-'0'
可以轻松实现转化
- 第二步:倒
竖式运算的核心在于位数要对齐,而正着存入数组时显然没有做到这一点,所以需要倒着放进去
在实际代码的实现中,一二步其实时一起进行的
for(i=0;i<n1;i++){
a[i]=str1[n1-i-1]-'0';
}
for(i=0;i<n2;i++){
b[i]=str2[n2-i-1]-'0';
}
-
核心思想:
高精度减法其实就是小学数学竖式运算,原理也来源于此,即该位减不过时向上一位借
1
,同时本位加10
-
第三步:减
该步实现具体的竖式运算,当被减数的本位小于减数时借位即可,借位也要有位可借才行,所以通常以大减小,
以小减大的情况将在后文讨论
for(int i=0;i<n;i++){
if(a[i]<b[i]){
a[i]+=10;
a[i+1]-=1;
}
a[i]-=b[i];
}
- 第四步:输出
在输出结果之前,首先需要清除前导0,
举个例子:123-123
,按上面的方法算下来应该时000
,这明眼人一看就知道这结果有问题,所以就需要清除多余的0
,而为了不清掉最后一个0
还需要加一个n>0
的限制条件
while(a[n]==0&&n>0){
n--;
}
while(n>=0){
printf("%d",a[n]);
n--;
}
到这里大体思路其实已经完成了,但还需要处理一些细节问题:
-
如果被减数小于减数怎么办?
-
所以在第一步的时候应该做一些特殊处理,在存入整型数组的时候先判断两数大小,字符串的一堆函数就注定了这个判断是要在存入之前进行,
strcmp
函数真的很好用,比较一下两个字符串 -
但这个时候又蹦出来一个问题,
56
和123
这种比较不就又出事了,所以还需要加入判断两个字符串长度的条件比较 -
当然,不能忘了输出负号,更改一下倒序输出的逻辑,以确保最终输出是大减小可以借位的情况下进行,不然会出现
10-20=-9
的奇观
-
各部分解析完成,整体代码如下:
#define t 1000010
int main(){
char str1[t],str2[t];
scanf("%s%s",str1,str2);
int a[t]={0},b[t]={0};
int n1=strlen(str1),n2=strlen(str2);
int n=n1;
if(n<n2){
n=n2;
}
if((n1==n2&&strcmp(str1,str2)>0)||n1>=n2){
for(int i=0;i<n1;i++){
a[i]=str1[n1-1-i]-'0';
}
for(int i=0;i<n2;i++){
b[i]=str2[n2-1-i]-'0';
}
}
else{
for(int i=0;i<n2;i++){
a[i]=str2[n2-1-i]-'0';
}
for(int i=0;i<n1;i++){
b[i]=str1[n1-1-i]-'0';
}
printf("-");
}
for(int i=0;i<n;i++){
if(a[i]<b[i]){
a[i]+=10;
a[i+1]-=1;
}
a[i]-=b[i];
}
while(a[n]==0&&n>0){
n--;
}
while(n>=0){
printf("%d",a[n]);
n--;
}
return 0;
}