洛谷部分题解

  • Post author:
  • Post category:其他


部分题面对题解

p1100:

题目描述

给出一个小于2^{32}232的正整数。这个数可以用一个3232位的二进制数表示(不足3232位用00补足)。我们称这个二进制数的前1616位为“高位”,后1616位为“低位”。将它的高低位交换,我们可以得到一个新的数。试问这个新的数是多少(用十进制表示)。

例如,数13145201314520用二进制表示为0000 0000 0001 0100 0000 1110 1101 100000000000000101000000111011011000(添加了1111个前导00补足为3232位),其中前1616位为高位,即0000 0000 0001 01000000000000010100;后1616位为低位,即0000 1110 1101 10000000111011011000。将它的高低位进行交换,我们得到了一个新的二进制数0000 1110 1101 1000 0000 0000 0001 010000001110110110000000000000010100。它即是十进制的249036820249036820。

输入格式

一个小于2^{32}232的正整数

题目解析:

这个题最重要的的进行十进制转化成为二进制,再通过将二进制输入到char 类型的一个32位的数组当中,从而改变其进制表达,然后需要的是将前十六位和后十六位进行互换,这样才可以确保会发生改变,最后一步需要将这个二进制的数字再一次转化成为十进制。这一步的操作相似于最开始的那一步,从而再将他给输出即可,如果不会二进制和十进制相互转化的话也是可以解决的

二进制转化十进制的思想逻辑和计算机基础的二进制转化逻辑相同,将数字进行对二的取余假如为0泽为0,当出现余数为1时,得到这个数位为1,最后将这个整体倒过来,便可以得到答案,二进制转十进制则是对高位进行二的减一次方的改变,假如这个样子的话,其实并不需要特别麻烦的步骤,仅仅只需要递归等方法便可以得到特殊的数字。

用复杂的方式写完便可以得到这个题的答案,

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<math.h>
unsigned int  a=0,num,start=pow(2,16);
unsigned int  b[16];
int main()
{
    scanf("%u",&a);
    for(int i=0;i<16;i++){
        if(1 & a){
            b[i]=1;
        }
        a>>=1;
    }
    num+=a;
    for(int i=0 ;i<16;++i){
        if(b[i]){
            num+=start;
        }
        start*=2;
    }
    printf("%u",num);
    return 0;
}

(转载他人的源代码)

题目描述

出题是一件痛苦的事情!

相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!

好吧,题目是这样的:给出一串数以及一个数字 CC,要求计算出所有 A – B = CA−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入格式

输入共两行。

第一行,两个整数 N, CN,C。

第二行,NN 个整数,作为要求处理的那串数。

输出格式

一行,表示该串数中包含的满足 A – B = CA−B=C 的数对的个数。

这个题是相对简单的题目,相较而言,首先只需要输入两个值,第一个作用是为这个要计算的确定一个数组的大小,在这个数组当中,重要的是对其中的值进行做差,这个有两种思路,第一种是是使用递归的思路,第二种是在程序当中直接使用for循环,直接将这个进行转换,在一次次的遍历之中得到最后的结果。值得注意的是是,这两种方法都是可以得到最后结果的,关键在于直接在函数当中使用for循环容易导致的是潮湿,因为这样可能会调用大量的内存,使用函数或者递归我并不能得到减少内存减少使用的解释,那么我的代码是这个样子的:

#include<stdio.h>
int main(){
    long long a,n;
    scanf("%lld %lld",&a,&n);
    int c=0;
    long long az[a];
    for(long long i=0;i<a;i++){
        scanf("%lld",&az[i]);
    }
    for(long long i=0;i<a;i++){
        for(long long p=0;p<a;p++){
            if(az[i]-az[p]==n){
                c++;
            }
        }
    }
    printf("%d",c);
}

但这样确实会造成一个严肃的问题,即时间的长度,也就是说,可能导致目标程序超过时间的限制。在网上并没有得到特别好的办法对我这个问题进行解决所以我暂时将这个问题放在这里,同时有一个c++写的代码对于我来说比较简洁,将这个代码放在这里,希望有人可以帮我

#include <cstdio>
#include <cstring>
#include <iostream>
#include<bits/stdc++.h>
#include<map>
using namespace std;
const int N = 2e5+10;
long long int k[N];
map<long long int , long long int >m;
int main()
{
	int n;
	long long c;
	long long ans = 0;
	cin >> n >> c;
	for(int i = 1 ; i <= n ; i++)
	{
		cin >> k[i];
		m[k[i]]++;
		k[i] = k[i] - c;
	}
	for(int i = 1 ; i <= n ; i++)
	{
		ans+=m[k[i]];
	}
	cout << ans << endl;
	return 0;
}

p5534:

题目描述

小 X 给了你一个等差数列的前两项以及项数,请你求出这个等差数列各项之和。

等差数列:对于一个 nn 项数列 aa,如果满足对于任意 i \in [1,n)i∈[1,n),有 a_{i+1} – a_i = dai+1​−ai​=d,其中 dd 为定值,则称这个数列为一个等差数列。

输入格式

一行 33 个整数 a_1, a_2, na1​,a2​,n,表示等差数列的第 1,21,2 项以及项数。


数据范围:

  • |a_1|,|a_2| \le 10^6∣a1​∣,∣a2​∣≤106。
  • 3 \le n \le 10^63≤n≤106。

输出格式

一行一个整数,表示答案。

这个题并没有什么特别的难度,重要的地方是来自数据的关于巨大,则我认为应该在这个程序中只需要进行数据的扩大化,将常规使用的int 改编成为long long 使得原本只会占据四个字节的数据进行改变,这里并不能使用unsigned将其改变,毕竟这里还是存在一个负数的情况。

那么将很简单了:

#include<stdio.h>
int main()
{
    int a,b,c;
    scanf("%d %d %d",&a,&b,&c);
    long d=b-a,s=a;
    for(int i=1;i<c;++i)s+=d*i+a;
    printf("%ld",s);
    return 0;
}

p1162

在这个题目当中,需要对被包围起来的0进行改变,用他的说法则为涂色。重点并不在涂色的改变的是什么,重点是如何将这里的进行完改变。常规的方法利用到了多重循环的嵌套,同时也将这个程序复杂化了。其代码是这个样子:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
typedef long long ll;
int xx[]={1,-1,0,0},yy[]={0,0,1,-1},n;
int a[32][32]={0},b[32][32]={0};

void dfs(int x,int y)
{
	for(int i=0;i<=3;i++)
	{
		int dx=x+xx[i],dy=y+yy[i];
		if(dx>=0&&dx<=n+1&&dy>=0&&dy<=n+1)
		{
			if(a[dx][dy]==1||a[dx][dy]==3)
			{
				continue;
			}
			else
			{
				a[dx][dy]=3;
				dfs(dx,dy);
			}
		}
	}
}

int main()
{
	int i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			scanf("%d",&a[i][j]);
			b[i][j]=a[i][j];
		}
	}
	dfs(1,1);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			if(a[i][j]==0)
			{
				b[i][j]=2;
			}
			printf("%d ",b[i][j]);
		}
		printf("\n");
	}
	return 0;
}

但我觉得这个题并不是不可简化,他说的这里存在一个圈,将这个0进行了一个画圈,但这里并不需要这个特别麻烦的嵌套,在这个题目当中,我可以对其进行判断,在没有遇到1的时候,我可以将0改编成为3,用来避免2和1。当再一次遇到1的时候我先对这一行进行一个判断,如果说只有两个1的话,我将把这个第二次遇到的进行一次改变,及在第二次遇到1之前不对其中的0进行改变,但在发现第二个1之后便继续将其中的0改编成为3,在多个存在的1时判断是不是相连的,如果没有相连,那么在间隔的地方进行改变,最后在改变的遍历结束之后,将这个程序中的0都改变成为2,但在发生改变成为3的地方仅仅只将3改变成为0即可

p5082

题目描述

小奔的期末考试结束了。

他的成绩不久之后就会发下来。

给出一个考试成绩表格,例如:

科目/分值种类 语文 数学 英语
满分 100100 120120 150150
实际得分 9999 7373 100100

当然。学校的老师认为如果录入如此多的成绩不好算分,于是他想要你的综合成绩评定

综合成绩评定指:(每一科的满分之和*3-每一科的实际得分之和*2)÷每科所扣除分数的和。

小奔想请你给出他的综合成绩,你能做到吗?

输入格式

第一行给出一个整数nn,表示科目的总数。 第二行nn个整数a_iai​,表示第ii门课程的满分。 第三行nn个整数b_ibi​,表示第ii门课程小奔的实际得分。

输出格式

一行一个数,表示他的综合成绩。结果保留6位小数

这个题和上面大体相似,没有什么特别的难点,但在这里只需要一个特别的地方,和上一个题相同,这个题相同的问题是数据的超量,即不可以说是int 即可以解决的问题,在这里通过对下面的数据分析,发现有一个特别的地方,就是n是小于1e7那么这个刚刚好是卡在了double的要求的点上,而且还要求了六位的小数,那么就是很简单了,注意double使用的是%lf即可。

#include<stdio.h>
double a,b,c,d,sum;int n,i;
int main(){
    scanf("%d",&n);
    for(i=1;i<=n;i++){
       scanf("%lf",&a);
       c+=a;
    }
    for(i=1;i<=n;i++){
        scanf("%lf",&b);
        d+=b;
    }
    sum=(c*3-d*2)/(c-d);
    printf("%0.6lf",sum);
    return 0;
}
#include<stdio.h>
int main(){
    double a,b,c;
    double a1,b1,c1;
    double n;
    scanf("%lf",&n);
    scanf("%lf %lf %lf",&a,&b,&c);
    scanf("%lf %lf %lf",&a1,&b1,&c1);
    double az=0,aq=0;
    aq=(a+b+c)*3-(a1+b1+c1)*2;
    printf("%lf\n",aq);
    az=aq/(a+b+c-a1-b1-c1);
    printf("%0.6lf",az);
}

在测试当中这两个源代码都是可以直接出来结果的,但没有直接进行测试全部,如果有问题希望得到解答。



版权声明:本文为m0_60512979原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。