hihocoder#1051(OJ不过)

一、越学越慌

真是越学越慌,发现自己大一大二没搞事,愧为计算机人,下面说说本人今天的经历

1、怎样获得数组的长度

先看看一位老哥的代码

#include<iostream>
using namespace std; 
int main(void)
{	
    int n;	
    cin >> n;	
    int *d;	
    int c[100];	
    for (int i = 0; i < n; i++)		
        cin >> c[i];	
  	d = c;	
    cout << "size:" << sizeof(d)-1 << endl;	
    return 0;
    }

效果如下:
在这里插入图片描述
至此明白,求数组长度不像求字符串一样有函数(strlen)或者’\0’结尾,我们要用sizeof数组头求,但是……

#include<stdio.h>
#include <stdlib.h>
int  main()
{
	int d[3];
	int *t = d;
	printf("%d %d\n", sizeof(d), sizeof(t)); 
	system("pause");
}

结果是 12 8
那么

  1. sizeof怎么用???
  2. 为什么sizeof指针长为8字节?

2、sizeof怎么用,sizeof指针是?

sizeof用法:参考自此
指针宽度问题:参考自此

数组的sizeof值等于数组所占用的内存字节数,如:
  • char a1[] = “abc”;
    sizeof( a1 ); // 结果为4,字符 末尾还存在一个终止符
  • int a2[3];
    sizeof( a2 ); // 结果为3*4=12(4的值依赖于int长度)
与上文的数组长度联系起来~~
void foo3(char a3[3])
{
int c3 = sizeof( a3 ); // c3 == 4
}

这里函数参数a3已不再是数组类型,而是蜕变成指针,相当于char* a3
为什么呢??仔细想想就不难明白,我们调用函数foo1时,程序会在栈上分配一个大小为3的数组吗不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为4。

指针宽度与寻址

不同类型的变量的地址所占的字节数都是一样的,意思是什么,就是
int ,char*,double *,long *等宽度都是一样的,不信你看,在vs上试试

#include<stdio.h>
#include <stdlib.h>
int  main()
{

	int i;
	int *ia = &i;
	printf("int : %d      ", sizeof(i));
	printf("int * : %d \n", sizeof(ia));
	char c;
	char *ca = &c;
	printf("char : %d      ", sizeof(c));
	printf("char * : %d \n", sizeof(ca));
	long l;
	long *la = &l;
	printf("long : %d      ", sizeof(l));
	printf("long * : %d \n", sizeof(la));
	double d;
	double *da = &d;
	printf("double : %d      ", sizeof(d));
	printf("double * : %d \n", sizeof(da));
	system("pause");
}

结果如下

int  : 4      	 int *  : 8
char : 1     	 char * : 8
long : 4     	 long * : 8
double : 8     	 double * : 8

可能有疑问了,上面的那个人文章里说char *是4个字节的,咱们我试的是8个字节呢,这就要说到计算机的寻址能力

3、32位机 64位机寻址能力与数据模型

寻址能力(参考自此

、什么叫寻址空间? 寻址空间一般指的是CPU对于内存寻址的能力。通俗地说,就是能最多用到多少内存的一个问题。数据在存储器(RAM)中存放是有规律的 ,CPU在运算的时候需要把数据提取出来就需要知道数据在那里 ,这时候就需要挨家挨户的找,这就叫做寻址,但如果地址太多超出了CPU的能力范围,CPU就无法找到数据了。 CPU最大能查找多大范围的地址叫做寻址能力 ,CPU的寻址能力以字节为单位。
地址总线为N位(N通常都是8的整数倍;也说N根数据总线)的CPU寻址范围是2的N次方字节,即2^N(B)。
、16位、32位、64位通常指的是什么? 从CPU的发展史来看,从以前的8位到现在的64位,8位也就是CPU在一个时钟周期内可并行处理8位二进字符0或是1,就以此类推是64位就64位二进制.

好了,看了上面两段话差不多就是32位机可以找2^32个地址,找一空间,这个空间需要32bits来标识。32/8=4字节,那么 char *之类所占位数是4咯。
而我的机子64位,就8位了。

问题又来了,为什么,我的64位机子long类型只有4字节宽度???

数据模型 参考此博文

你去百度:数据类型宽度,有一大票会说64位下long是8位宽。
为什么???看下面这张表,这个才具体

TYPELP32ILP32LP64ILP64LLP64
CHAR88888
SHORT1616161616
INT1632326432
LONG3232646432
LONG LONG6464646464
POINTER3232646464

windows 64位系统用的是LLP64的数据模型,明白了,这话不敢说。
这儿还有一个英文网站具体看看

二、开始做题

1、题目要求:

描述

小Ho给自己定了一个宏伟的目标:连续100天每天坚持在hihoCoder上提交一个程序。100天过去了,小Ho查看自己的提交记录发现有N天因为贪玩忘记提交了。于是小Ho软磨硬泡、强忍着小Hi鄙视的眼神从小Hi那里要来M张"补提交卡"。每张"补提交卡"都可以补回一天的提交,将原本没有提交程序的一天变成有提交程序的一天。小Ho想知道通过利用这M张补提交卡,可以使自己的"最长连续提交天数"最多变成多少天。

输入

第一行是一个整数T(1 <= T <= 10),代表测试数据的组数。
每个测试数据第一行是2个整数N和M(0 <= N, M <= 100)。第二行包含N个整数a1, a2, … aN(1 <= a1 < a2 < … < aN <= 100),表示第a1, a2, … aN天小Ho没有提交程序。

输出

对于每组数据,输出通过使用补提交卡小Ho的最长连续提交天数最多变成多少。

样例输入

3  
5 1  
34 77 82 83 84  
5 2  
10 30 55 56 90  
5 10  
10 30 55 56 90

样例输出

76  
59
100

2、解题

  • 第一个点的东西基本上没用到代码里,用函数间传递数组长度参数避免这个问题了,前面的纯属找事!!!
  • 先说明,我做题不过oj,就是自己嗨的,只在自己的vs上跑,也经历没大量数据。所以,欢迎指出错误!

下面的代码输出格式不合题意,只核心功能想通

#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int loop(int t, int b, int n, int a, int *N, int *flag);
int fill(int *N, int n, int m);
int count(int *N, int n);
int  main()
{
	int t;
	int n, m;//长度
	int N[100];
	scanf_s("%d", &t);
	for (int i=0; i<t; i++)
	{
		scanf_s("%d %d", &n, &m);
		for (int c = 0; c < n; c++)
			scanf_s("%d", &N[c]);
		fill(N,  n, m);
	}	
	
	system("pause");
}
int loop(int t, int b, int n, int a, int *N, int *flag)
//t是当前找了多少个,b是下一层递归从哪儿开始找,n是缺卡天的数组
//a是从n中选a个(a=n-m),N是原始数组
//flag是选择后元素数为a的数组,表示这几天补不了
{
	if (t == a)
	{
		printf("如果这几天不补卡--->  ");
		for (int c = 0; c < a; c++)
			printf("%d  ", flag[c]);
		printf("    那么最多可连续打卡%d天\n", count(flag, a)); 
		return 0;
	}
	else
	{
		for (int i = b; i < n - a + 1 + t; i++)
		{
			flag[t] = N[i];
			loop(t + 1, i+1,n, a, N, flag);
		}
	}
}

int fill(int *N,  int n, int m)//loop外的部分
{
	int a = n - m;
	int *flag= (int *)malloc(sizeof(int) * a);
	if (n <= m)
		printf("不慌不慌,全部可以补");
	else
		loop(0, 0,n, a, N, flag);
	return 0;
}
int count(int *N, int n)//计算N中最长连续天数
{
	int leng=0, temp;
	leng = N[0] - 1;
	for (int i = 1; i < n; i++)
	{
		temp = N[i] - N[i - 1] - 1;
		leng = temp > leng ? temp : leng;
	}
	temp = 100 - N[n - 1]-1;
	leng = temp > leng ? temp : leng;
	return leng;
}

输出如下

3
5 1
34 77 82 83 84
如果这几天不补卡--->  34  77  82  83      那么最多可连续打卡42天
如果这几天不补卡--->  34  77  82  84      那么最多可连续打卡42天
如果这几天不补卡--->  34  77  83  84      那么最多可连续打卡42天
如果这几天不补卡--->  34  82  83  84      那么最多可连续打卡47天
如果这几天不补卡--->  77  82  83  84      那么最多可连续打卡76天
5 2
10 30 55 56 90
如果这几天不补卡--->  10  30  55      那么最多可连续打卡44天
如果这几天不补卡--->  10  30  56      那么最多可连续打卡43天
如果这几天不补卡--->  10  30  90      那么最多可连续打卡59天
如果这几天不补卡--->  10  55  56      那么最多可连续打卡44天
如果这几天不补卡--->  10  55  90      那么最多可连续打卡44天
如果这几天不补卡--->  10  56  90      那么最多可连续打卡45天
如果这几天不补卡--->  30  55  56      那么最多可连续打卡43天
如果这几天不补卡--->  30  55  90      那么最多可连续打卡34天
如果这几天不补卡--->  30  56  90      那么最多可连续打卡33天
如果这几天不补卡--->  55  56  90      那么最多可连续打卡54天
5 10
10 30 55 56 90
不慌不慌,全部可以补请按任意键继续. . .

排列组合???

没错,里面用到了一个排列组合的东东,我写了一个递归,迷之递归,貌似没毛病。
写这一坨之前也百度过排列组合,但是看了两句,愚笨不懂,就打算先自己摸索了。
递归真有趣

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值