2024年2月28号题解

P4994 终于结束的起点

解题思路

  1. 通过加法同余原理可以知道f[i] % m == 0,那么f[i - 1] % m = 1,所有把f[i + 1] % m = 1转换成了f[i - 1] % m = 1的问题
  2. 那么只需要填好斐波那契数列再判断就可以了,又因为斐波那契可能会超出int的范围那么我们对每一项斐波那契再取模就可以了

代码实现

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf 
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 10000001

ll m;
ll f[N];
ll i;

int main(int argc, char* argv[])
{
	sc("%lld", &m);
	
	f[1] = f[0] = 1;//初始化
	i = 2;//从第二项开始
	
	while(1) {
		f[i] = (f[i - 1] + f[i - 2]) % m;//对于每一项都取模
		if (f[i] % m == 0 && f[i - 1] % m == 1) {//如果满足条件代表找到了
			break;
		}
		i ++;//看下一项
	}
	
	pr("%lld", i + 1);//因为从0开始时数,所以要加一

	return 0;
}

P1025 [NOIP2001 提高组] 数的划分

解题思路

  1. 难点在于怎么不重复的选择方案的个数,那么我们可以通过在递归中使用一个变量来记录上一次选取的数,然后让选取的数从上一次选取的数开始选,就像算一个些数的组合一样来避免重复选取
  2. 可以通过i <= n - sum来进行剪枝,因为i的最大范围只能是n - sum

代码实现

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf 
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 10

int n, k;//整数n和被分成的份数 
int ans;//方案个数 

void dfs(int cur, int sum, int last) {//cur代表当前选择了几个数,sum代表选取数的累加和,last代表上一个选取的数 
	if (cur == k) {//如果选取了k个数了 
		if (sum == n) {//如果sum等于n满足条件,因为用了last变量所以不可能出现重复的方案,所以直接加 
			ans ++;//答案加一 
		}
		return ;
	}
	
	for (int i = last; i <= n - sum ; i ++) {//从上一个选取的数开始,i最大范围为n - sum来进行剪枝 
		dfs(cur + 1, sum + i, i);//递归调用 
	}
}

int main(int argc, char* argv[])
{
	sc("%d%d", &n, &k);
	
	dfs(0, 0, 1);//dfs求解方案数 
	
	pr("%d", ans);
	
	return 0;
}

P1003 [NOIP2011 提高组] 铺地毯

解题思路

  1. 用一个二维数组记录地毯的左下角和x轴和y轴的长度
  2. 从后开始遍历数组,因为后面的会覆盖前面的地毯,所以可以从后往前遍历
  3. 判断点在那个地毯里面,在就输出,访问完了所有地毯如果都没有在的话就输出-1

代码实现

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf 
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 10001

int a[N][4];//存储地毯的信息 
int t[2];//存储访问的位置 
int n;//地毯的个数 

int f() {//返回t位置被那个地毯覆盖 
	int ans = -1;//返回的地毯编号 
	
	for (int i = n - 1; i >= 0; i --) {//从后开始遍历,因为会被后面的地毯覆盖 
		if ((t[0] >= a[i][0] && t[0] <= a[i][0] + a[i][2]) && (t[1] >= a[i][1] && t[1] <= a[i][1] + a[i][3])) {//判断这个点在不在i号地毯里面 
			return i + 1;//在就直接返回 
		}
	}
	
	return ans;//如果没有在for循环里面返回代表没有在任何一个地毯里面,所有返回-1 
}

int main(int argc, char* argv[])
{
	sc("%d", &n);
	
	//读入地毯信息 
	for (int i = 0; i < n; i++) {
		sc("%d%d%d%d", a[i], a[i] + 1, a[i] + 2, a[i] + 3);
	}
	
	sc("%d%d", t, t + 1);//读入查询位置 
	
	pr("%d", f());//打印被覆盖的地毯 
	
	return 0;
}

总结

  1. 很自然的想法是用一个二维数组来模拟铺地毯的过程,但是因为0a,b,g,k10^5,所以开一个二维数组不行
  2. 那么下一个想法是存储地毯的信息,来遍历地毯看点在那个地毯里面来解决问题,然后刚开始是一个点一个点试,所以超时
  3. 那么有没有一种办法可以直接判断点在不在一个坐标系中的长方形中呢
  4. 有,用数学的知识就可以了,只要点的x和y坐标在长方形的中间,那么就代表在这个地毯中

P1179 [NOIP2010 普及组] 数字统计

解题思路

  1. 遍历区间中的每一个数,并对区间中的每一个分离它的每一位并且判断是不是2,是2就让计数器加一,不是就去看下一个数

代码实现

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf 
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 10

int l;
int r;
int ans;//答案 

void f(int n) {//判断一个数中2的个数 
	while(n) {
		if (n % 10 == 2) {//如果一个数有二 
			ans ++;//计数器加一 
		}
		n /= 10;//看下一位 
	}
}

int main(int argc, char* argv[])
{
	sc("%d%d", &l, &r);//读入左端点和右端点 
	
	while(l <= r) {//遍历区间中的每一个数 
		f(l++);//累加遍历数中2的个数 
	}
	
	pr("%d", ans);///打印结果 
	
	return 0;
}

 

posted @ 2024-02-28 21:55  lwj1239  阅读(31)  评论(0)    收藏  举报