第12周 学习总结

1.取余处理;

真的服,一道题环绕我好久,真无语。

#include<stdio.h>
#define mol (int)(1e9+7)
int  a[2030000] = { 1,2 };

int main() {
	int t, n;
	scanf("%d", &t);
	for (long long i = 2; i <= 200000; i++)
		a[i] = (a[i - 1]%mol + a[i - 2]%mol  + (i * (i+1)/ 2) % mol) % mol;

	while (t--)
	{
		scanf("%d", &n);
		
		
		printf("%d\n", a[n-1]);
	}
	return 0;
}

这里面最大的坑,有两个,一个是i从0开始所以我的函数应该是i*(i+1);而不是i*(i-1);

真的无语,还有一个就是i的类型,因为i最大为200000,所以i*i可能会超出数据类型最大值,所以要设立long long型,这是最大的坑,又是数据类型的,踩了好多次了,哎,这题真是烦了好久!

2.插入排序

题目:

#include <stdio.h>
int main() {
	void sort(int a[], int k);
	int T, n, a[1000], k;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
			scanf("%d", &a[i]);
		scanf("%d", &k);
		sort(a, k);
		for (int i = 0; i < n; i++)
			printf("%d ", a[i]);

	}


	return 0;
}
void sort(int a[], int k)
{
	int i = 0, j = 0, t;
	for (i = 1; i <= k; i++)
	{
		t = a[i];
		j = i - 1;
		while (j >= 0 && a[j] > t) {
			a[j+1] = a[j];
			j--;
		}
		a[j + 1] = t;
	}
}

这里的k代表这第k趟排序,如果k=n-1时便能全部排好,详情http://t.csdnimg.cn/oPj6J

3.二分法

这个数据太大,要超时,所以用二分法;(这里的数是排好序的)

二分查找运用于排好序中,找某个数,因为这堆数很多,就容易超时,就运用二分法;
#include <stdio.h>
#define maxn (int)1e6
int a[maxn];
int main() {
	int n;
	int left,k, right,m,taget,mid;
	 scanf("%d%d", &n,&m);
	 for (int i = 1; i <= n; i++) {
		 scanf("%d", &a[i]);
	 }
	 while (m--) {
		 k = -1;
		 scanf("%d", &taget);
		 left = 1; right = n ;
		 while (left < right) {
			 mid = (left + right) / 2;
			 if (a[mid] >= taget)right = mid;
			 else if (a[mid] < taget)left = mid + 1;			 
		 }		
		 if (a[left] == taget)
			 printf("%d ", left);
		 else printf("-1 ");
	 }
	return 0;
}
总结:感觉思维被固化了,题目改变了点点就感觉迷迷糊糊的;
二分法主要是找一个数,所以后面跳出while循环也是要left等于right时,那么最终就只能是一个值,
这里找的时最左边的元素,那么我们可以用左闭区间右边开区间来进行二分法;
模板一:
while (l < r)
{
	int mid = (r + l) / 2;
	if (a[mid >= taget])r = mid;    //这里用了闭区间,并且这里的r没有加1;注意,这里相当于一直往靠,因为当区间内的数相同
	                                //时这里一直时右边界在移动。
	else l = mid + 1;                 //这里的a[mid]一定是不等于taget的所以要加个一      
}

相反:如果想往有边界靠;
模板二:
这里就是if(a[mid] <= taget)l = mid;
else  if (a[mid] > taget)r = mid - 1;
4.前缀和差分(一维,二维)

题目:

解题:

int n, p, i, min;
int  a[1005000], d[1005000];
#include<stdio.h>
int main() {

	scanf("%d%d", &n, &p);
	for (i = 1; i <= n; i++)
	{                            //一维的差分;这里a[0]为0;所以d【0】=a【0】;以至于后面可以通过求前缀和算该数字;
		scanf("%d", &a[i]);              //这样很可能就是中间改变一些值能快速的求出区间和;
		d[i] = a[i] - a[i - 1];
	}
	while (p--) {
		int r, l, z;
		scanf("%d%d%d", &r, &l, &z);
		d[r] += z;
		d[l+1] -= z;
	}
	for (i = 1; i <= n; i++)
		d[i] += d[i - 1];
	min = d[1];
	for (i = 1; i <= n; i++)
		if (d[i] < min)min = d[i];
	printf("%d", min);
	return 0;
}
二维差分,前缀和:

解题:

#include <stdio.h>
#define N 10000
int d[N][N];
int sum[1000][1000];


//void Sert(int x1, int y1, int x2, int y2)
//{
//	d[x1][y1] += 1;
//	d[x2 + 1][y1] -= 1;
//	d[x1][y2 + 1] -= 1;
//	d[x2 + 1][y2 + 1] += 1;  
//}

//原数组就可以用这个函数输入,当x1,x2相等还有y1和y2相等时这里相当于输入输入原数组,并且这样这样可以直接把

		//void type(int a[N][N], int sum[N][N])       //前缀和数组,这里可以把d[][]传入a[][]那末这个前缀和就是原数组
		//{                                          
		//	for (int i = 1; i <= N; i++)
		//	{
		//		for (int j = 1; j <= N; j++) {
		//			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][i - 1] + a[i][j];
		//		}
		//	}
		//}

void type1(int x1, int y1, int x2, int y2, int c)   //全局定义这个差分数组
{
	d[x1][y1] += c;
	d[x2+1][y1] -= c;
	d[x1][y2 + 1] -= c;
	d[x2+1][y2+1] += c;
}
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	int x1, y1, x2, y2;
	/*for(int i=1;i<=n;i++)
		for (int j = 1; j <= n; j++) {
			scanf("%d", &a[i][j]);
			type1(i, j, i, j, a[i][j]);}
			这里可以进行算初始差分;
	*/

	for (int i = 1; i <= m; i++)
	{
		scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
		type1(x1, y1, x2, y2, 1);
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			sum[i][j] = d[i][j] - sum[i - 1][j - 1] + sum[i][j - 1] + sum[i - 1][j];
			printf("%d ", sum[i][j]);
		}
		printf("\n");
	}

	return 0;
}

差分就是该位置与前一个位置的差,那么差分的前缀和就是原数组,运用前缀和可以快速算出区间和(区间的值改变后),因为改变后要循环改值会需要很多时间,运用这个前缀和可以快速算区间和,而差分和前缀和一起运用起来,就可以快速改变(进行多次增减值)值,

二维数组

差分模板:

这里很容易错,注意模板的+1;

5.快速排序
void quicksort(int a[], int L,int R)
{
	if (L >= R)return;
	int left = L, right = R;
	int key = a[left];
	while (left < right) {
		while (a[right] >= key && left < right)right--;
		a[left] = a[right];
		while (a[left] <= key && left < right)left++;
		a[right] = a[left];
		if (left >= right)a[left] = key;
	}
	quicksort(a, L, right - 1);
	quicksort(a, right+1, R);
}

找一个key,通常找数列左边第一个,两边的区间left和right不断缩进,小于key在左边,大于key在右边;时间复杂度nlogN;

这周还行,一般般,但是浮躁了一些,希望下周要沉淀下来,可怕的感冒快快离去

  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值