YF的“愉快”一周(第三周)

目录

一,双指针

类型:

经典题目(尺取法)

题目练习

A---判断回文字符串

B--- A-B 数对(三指针)

C---Unique Snowflakes

D---Subsequence

二,二分查找

 模板一(通过middle找结果):

模板二(left==right):

模板三(小数二分):

题目练习

A---  A-B数对(二分法)

B---烦恼的高考志愿

三,二分答案

                二分查找与二分答案有何区别?

题目练习

A---木材加工

B---跳石头

C---Monthly Expense

四,前缀与差分

一维前缀(就是序列前n项累加)

二维前缀

一维差分

题目练习

A---Color the ball

B---Complete the Sequence

C---Tallest Cow

D---IncDec Sequence

五,倍增法与ST算法

        模板题:

题目练习

六,排序(快速排序和归并排序)

(1)归并排序

(2)快速排序

题目练习

A---逆序对

七,快速幂

模板

简化版


一,双指针

类型:

(1)两个指针,方向不同;(数组内找特定的值,由两个元素相加)

(2)两个指针,方向相同;(合并数组)

(3)两个指针,一快一慢;(检查单链表是否存在“环”)

(4)两个指针,方向相同,起点不同(找到链表倒数第n个节点)

经典题目(尺取法)

1,在一个升序数列的数组中,找到两个数,使得这两个数等于给定的值

//数组{1,3,5,6,8,9}  给定值val=11,给出数组下标1,4
#include<bits/stdc++.h>
using namespace std;

int* f(int* a, int size, int val)
{
    int begin = 0;
    int end = size - 1;//两个数组下标,一头一尾
    while (begin < end) {
        if (a[begin] + a[end] > val) end--; //大了,尾部减一
        else if (a[begin] + a[end] < val) begin++;//小了,头部加一
        else if (a[begin] + a[end] == val) {
            int* ans = (int*)malloc(2 * sizeof(int));//建立动态内存,用于保存答案
            ans[0] = begin;
            ans[1] = end;
            return ans;
        }
    }
    printf("no answear!");//没有结果,输出"no answear!"
    return NULL;
}

int main()
{
    int a[] = { 1,3,5,6,8,9 };
    int size = sizeof(a) / sizeof(a[0]);
    int val = 11;
    int* ans = f(a, size, val);
    printf("%d %d", ans[0], ans[1]);
    return 0;
}

2.合并两个升序数组,并升序排列

//数组{1,3,5,6,8,9}和数组{2,4,7,9}
#include<bits/stdc++.h>
using namespace std;

int* f(int* a, int* b, int size_a, int size_b)
{
    int* ans = (int*)malloc(20 * sizeof(int)); //创建一个大的数组,保存元素
    int begin_a = 0, begin_b = 0,count=0;

    while (begin_a != size_a && begin_b != size_b) {//其中一个数组全部存入大数组,则终止循环
        if (a[begin_a] <= b[begin_b]) {//每组比较,小的进入并加一
            ans[count++] = a[begin_a++];
        }
        else ans[count++] = b[begin_b++];
    }

    //将剩下的数组全部存入大数组
    while (begin_a != size_a) {
        ans[count++] = a[begin_a++];
    }
    while (begin_b != size_b) {
        ans[count++] = b[begin_b++];
    }
    return ans;
}

int main()
{
    int a[] = { 1,3,5,6,8,9 };
    int b[] = { 2,4,7,9 };
    int size_a = sizeof(a) / sizeof(a[0]);
    int size_b = sizeof(b) / sizeof(b[0]);
    int* ans = f(a, b, size_a, size_b);
    for (int i = 0; i < size_a+size_b; i++) cout << ans[i] << " ";
    return 0;
}

题目练习

A---判断回文字符串

“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。请写一个程序判断读入的字符串是否是“回文”。

Input

输入包含多个测试实例,输入数据的第一行是一个正整数n,表示测试实例的个数,后面紧跟着是n个字符串。

Output

如果一个字符串是回文串,则输出"yes",否则输出"no".

Sample

InputcopyOutputcopy
4
level
abcde
noon
haha
yes
no
yes
no

实现:用双指针,一头一尾,判断是否相等

AC代码

#include<bits/stdc++.h>
using namespace std;

int check(string str, int n);

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        string str;
        cin >> str;
        if (check(str, str.length())) cout << "yes" << endl;
        else cout << "no" << endl;
    }
    return 0;
}

int check(string str, int n)
{
    int begin = 0, end = n - 1;
    while (begin <= end) {
        if (str[begin] != str[end]) return 0;
        begin++;
        end--;
    }
    return 1;
}

B--- A-B 数对(三指针)

给出一串正整数数列以及一个正整数 C,要求计算出所有满足 A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

Input

输入共两行。

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

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

Output

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

Sample 1

InputcopyOutputcopy
4 1
1 1 2 3
3

Hint

对于 75%的数据,1≤N≤2000。

对于 100%的数据,1≤≤N≤2×10^5,0≤ai​<2^30,1≤≤C<2^30。

实现:这题不能使用尺取法,会漏一些情况。可以使用三指针组成滑动窗口来解决。

AC代码

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;
long long a[N];

// 定义函数count_n用于计算数组中满足条件的子数组数量
long long count_n(long long* a, int n, long long val);

int main()
{
    int n;
    long long val;
    cin >> n >> val;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    sort(a, a + n); // 对数组a进行升序排序
    cout << count_n(a, n, val);
    return 0;
}

long long count_n(long long* a, int n, long long val)
{
    int begin = 0, end1 = 0, end2 = 0;
    long long count = 0;
    // 使用滑动窗口的方法查找满足条件的子数组
    while (begin < n) {
        // 移动end1和end2指针,直到a[end1] - a[begin] >= val 或者end1达到数组末尾
        while (a[end1] - a[begin] < val && end1 < n)
            end1++;
        // 移动end2指针,直到a[end2] - a[begin] > val 或者end2达到数组末尾
        while (a[end2] - a[begin] <= val && end2 < n)
            end2++;
        // 如果a[end1] - a[begin] == val,则表示找到了一个满足条件的子数组,更新count
        if (a[end1] - a[begin] == val)
            count = count + end2 - end1;
        // 移动begin指针,继续寻找下一个满足条件的子数组
        begin++;
    }
    return count;
}

C---Unique Snowflakes

Emily the entrepreneur has a cool business idea: packaging and selling snowflakes. She has devised a machine that captures snowflakes as they fall, and serializes them into a stream of snowflakes that flow, one by one, into a package. Once the package is full, it is closed and shipped to be sold. The marketing motto for the company is “bags of uniqueness.” To live up to the motto, every snowflake in a package must be different from the others. Unfortunately, this is easier said than done, because in reality, many of the snowflakes flowing through the machine are identical. Emily would like to know the size of the largest possible package of unique snowflakes that can be created. The machine can start filling the package at any time, but once it starts, all snowflakes flowing from the machine must go into the package until the package is completed and sealed. The package can be completed and sealed before all of the snowflakes have flowed out of the machine.

Input

The first line of input contains one integer specifying the number of test cases to follow. Each test case begins with a line containing an integer n, the number of snowflakes processed by the machine. The following n lines each contain an integer (in the range 0 to 109 , inclusive) uniquely identifying a snowflake. Two snowflakes are identified by the same integer if and only if they are identical. The input will contain no more than one million total snowflakes.

Output

For each test case output a line containing single integer, the maximum number of unique snowflakes that can be in a package.

Sample Input

1

5

1 2 3 2 1

Sample Output

3

理解:找到最长的一段连续的,且不重复的序列,输出这段序列的长度。

实现:使用滑动窗口方法查找具有不同元素的最长连续子序列

AC代码

#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
const long long N = 1e6 + 5;
long long a[N];

int main() {
    int T;
    cin >> T;
    for (int i = 0; i < T; i++) {
        long long n;
        cin >> n;
        for (int j = 0; j < n; j++) cin >> a[j];

        int left = 0, right = 0, max = 0;
        set<long long> s;
        for (left = 0; left < n; left++) {
            while (right < n && !s.count(a[right])) s.insert(a[right++]);//不同雪花则进入集合
            if (right - left > max) max = right - left;//获取最大值
            s.erase(a[left]);//left移动,删除要移动的元素
        }
        cout << max << endl;
    }
    return 0;
}

D---Subsequence

A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.

Input

The first line is the number of test cases. For each test case the program has to read the numbers N and S, separated by an interval, from the first line. The numbers of the sequence are given in the second line of the test case, separated by intervals. The input will finish with the end of file.

Output

For each the case the program has to print the result on separate line of the output file.if no answer, print 0.

Sample

InputcopyOutputcopy
2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
2
3

理解:编写一个程序,求序列中连续元素组成的子序列的最小长度,且子序列的总和大于或等于S

实现:本题使用滑动窗口,不用排序,直接求解

AC代码

#include<iostream>
#include<algorithm>
using namespace std;

int min_length(int* a, int n, int val);

int main()
{
	int T;
	cin >> T; 

	for (int i = 0; i < T; i++) 
	{
		int n, val;
		int a[101000];
		cin >> n >> val; // 读取序列的长度 n 和目标和 val

		for (int j = 0; j < n; j++)
			cin >> a[j]; // 读取序列的元素
		
		cout << min_length(a, n, val) << endl; // 输出满足条件的子序列的最小长度
	}
}


int min_length(int* a, int n, int val)
{
	int begin = 0, end = 0;
	int sum = 0;

	// 将窗口向右扩展,直到当前和 sum 大于等于目标和 val,记录窗口的结束位置
	for (end = 0; end < n; end++) {
		sum += a[end];
		if (sum >= val) break;
	}

	if (sum < val) return 0; // 如果当前和小于目标和 val,输出 0 表示没有满足条件的子序列

	int min_len = end - begin + 1; // 初始化 num 为当前窗口的长度

	// 移动窗口左边界,寻找满足条件的子序列的最小长度
	while (begin < n) {
		sum -= a[begin]; // 从窗口左侧缩小窗口,并减去对应的元素
		begin++;

		// 在窗口右侧扩展窗口,并增加对应元素,直到当前和大于等于目标和 val
		while (sum < val && end < n - 1) {
			end++;
			sum += a[end];
		}

		// 更新 min_len 为当前窗口的长度与之前的最小值
		if (sum >= val && min_len > end - begin + 1)
			min_len = end - begin + 1;
	}

	return min_len; // 输出满足条件的子序列的最小长度
}

二,二分查找

 模板一(通过middle找结果)

这个模板并不能解决“输出这个数字在序列中第一次出现的编号”这个问题,泛用性不强,只是提供一个思路

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int a[N];

int f(int* a, int n, int val);

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++) cin >> a[i];
	sort(a, a + n);
	for (int i = 0; i < m; i++) {
		int x;
		cin >> x;
		cout << f(a, n, x) << endl;
	}
	return 0;
}

int f(int* a, int n, int val)
{
	int left = 0, right = n - 1;
	while (left <= right) {//当left == right时,区间[left, right]仍然有效
		int middle = left + (right - left) / 2;//等同于 (left + right) / 2,这样写防止middle溢出
		if (a[middle] > val) right = middle - 1;
		else if (a[middle] < val) left = middle + 1;
		else return middle+1;//既不在左边,也不在右边,那就是找到答案了,返回下标
	}
	return -1;//没有找到目标值
}

模板二(left==right):

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int a[N];

int f(int* a, int n, int val);

int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i++) cin >> a[i];
    sort(a, a + n);
    for (int i = 0; i < m; i++) {
        int x;
        cin >> x;
        cout << f(a, n, x) << endl;
    }
    return 0;
}

int f(int* a, int n, int val)
{
    int left = 0, right = n - 1;
    // 使用二分查找算法
    while (left < right) {
        int middle = left + (right - left) / 2;
        if (a[middle] >= val) right = middle - 1;// 如果中间元素大于等于目标值
        else left = middle + 1;
    }
    // 当 left == right 时,区间 [left, right] 仍然有效
    // 检查 left 对应的元素是否为目标值
    if (left < n && a[left] == val)
        // 找到目标值,返回其位置(下标+1)
        return left + 1;
    else
        // 未找到目标值,返回-1
        return -1;
}

模板三(小数二分):

题目练习

A---  A-B数对(二分法)

给出一串正整数数列以及一个正整数 C,要求计算出所有满足 A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

Input

输入共两行。

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

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

Output

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

Sample 1

InputcopyOutputcopy
4 1
1 1 2 3
3

Hint

对于 75%的数据,1≤N≤2000。

对于 100%的数据,1≤≤N≤2×10^5,0≤ai​<2^30,1≤≤C<2^30。

实现:给出了C,我们要找出A和B。我们可以遍历数组,即让每一个值先变成B,然后二分找对应的A首次出现位置,看是否能找到。如果找到A,那就二分找最后出现的位置,继而,求出A的个数,即数对的个数。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int a[N];

int check(int* a, int n, int val);

int main()
{
    int n, target, count = 0;
    cin >> n >> target;
    for (int i = 0; i < n; i++) cin >> a[i];
    sort(a, a + n);

    // 遍历排序后的数组,查找满足条件的数对
    for (int i = 0; i < n; i++) {
        if (check(a, n, target + a[i]))
            count++;
    }

    // 输出满足条件的数对的个数
    cout << count << endl;
    return 0;
}

int check(int* a, int n, int val)
{
    int left = 0, right = n - 1;
    while (left < right) {
        int middle = left + (right - left) / 2;
        if (a[middle] >= val)
            right = middle - 1;
        else
            left = middle + 1;
    }

    // 当 left == right 时,区间 [left, right] 仍然有效
    // 检查 left 对应的元素是否为目标值
    if (left < n && a[left] == val)
        // 找到目标值,返回 1
        return 1;
    else
        // 未找到目标值,返回 0
        return 0;
}

B---烦恼的高考志愿

计算机竞赛小组的神牛 V 神终于结束了高考,然而作为班长的他还不能闲下来,班主任老 t 给了他一个艰巨的任务:帮同学找出最合理的大学填报方案。可是 v 神太忙了,身后还有一群小姑娘等着和他约会,于是他想到了同为计算机竞赛小组的你,请你帮他完成这个艰巨的任务。

题目描述

现有 m 所学校,每所学校预计分数线是 ai​。有 n 位学生,估分分别为 bi​。

根据 n 位学生的估分情况,分别给每位学生推荐一所学校,要求学校的预计分数线和学生的估分相差最小(可高可低,毕竟是估分嘛),这个最小值为不满意度。求所有学生不满意度和的最小值。

输入格式

第一行读入两个整数 m,n。m 表示学校数,n 表示学生数。

第二行共有 m 个数,表示 m 个学校的预计录取分数。第三行有 n 个数,表示 n 个学生的估分成绩。

输出格式

输出一行,为最小的不满度之和。

输入 #1

4 3
513 598 567 689
500 600 550

输出 #1

32

数据范围:

对于 30% 的数据,1≤n,m≤1000,估分和录取线 ≤10000;

对于 100%的数据,1≤n,m≤100000,估分和录取线≤1000000 且均为非负整数。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int a[N];

int min_school(int* a, int n, int val);

int main()
{
    int school, student;
    cin >> school >> student;
    for (int i = 0; i < school; i++) cin >> a[i];
    sort(a, a + school);//排序勿忘
    long long sum = 0;
    for (int i = 0; i < student; i++) {
        int x;
        cin >> x;
        sum += min_school(a, school, x);//累加每一位同学与学校的分差
    }
    cout << sum;
    return 0;
}

int min_school(int* a, int n, int val)
{
    int l = 0, r = n - 1;
    int min = 10000;//分差
    while (l <= r) {
        int mid = l + (r - l) / 2;
        if (fabs(val - a[mid]) < min) min = fabs(val - a[mid]);//记录最小分差
        if (a[mid] >= val) r = mid - 1;
        else l = mid + 1;
    }
    return min;
}

三,二分答案

二分查找与二分答案有何区别?

二分查找:在一个已知的有序数据集上进行二分地查找
二分答案:答案有一个区间,在这个区间中二分,直到找到最优答案

二分答案最典型的问题:求最大的最小值求最小的最大值

题目练习

A---木材加工

材厂有 n 根原木,现在想把这些木头切割成 k 段长度均为 l 的小段木头(木头有可能有剩余)。当然,我们希望得到的小段木头越长越好,请求出 l 的最大值。木头长度的单位是 cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。

例如有两根原木长度分别为 11 和 21,要求切割成等长的 6 段,很明显能切割出来的小段木头长度最长为 5。

输入格式

第一行是两个正整数 n,k分别表示原木的数量,需要得到的小段的数量。

接下来 n行,每行一个正整数 Li​,表示一根原木的长度。

输出格式

仅一行,即 l 的最大值。

如果连 1cm 长的小段都切不出来,输出 0

输入 #1

3 7
232
124
456

输出 #1

114

数据规模与约定

对于 100% 的数据,有 1≤n≤10^5,1≤k≤10^8,1≤Li≤10^8 (i∈[1,n]).

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int a[N];

// 检查在长度为val的情况下是否能切割得到至少m段小木头
bool check(int* a, int n, int val, int m);

int main()
{
	int n, m;
	cin >> n >> m;
	int l = 1, r = 0;

	// 输入原木的长度,并找到最大的原木长度r
	for (int i = 0; i < n; i++) {
		cin >> a[i];
		if (a[i] > r) r = a[i];
	}

	// 使用二分查找在长度为[l, r]的范围内查找答案
	while (l <= r) {
		int mid = l + (r - l) / 2;
		if (check(a, n, mid, m))
			l = mid + 1; // 答案可行,继续增加长度
		else
			r = mid - 1;
	}

	// l为满足条件的最大长度
	if (check(a, n, l, m))
		cout << l << endl;
	else
		cout << r << endl;
	return 0;
}

// 检查在长度为val的情况下是否能切割得到至少m段小木头
bool check(int* a, int n, int val, int m)
{
	int count = 0;
	// 计算每个原木可以切割得到多少小段木头,如果满足目标小段数量m,则返回true
	for (int i = 0; i < n; i++) {
		count += a[i] / val;
		if (count >= m)
			return true;
	}
	// 如果在所有原木上切割得到的小段数量之和大于等于m,则返回true
	if (count >= m)
		return true;
	return false;
}

B---跳石头

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。

Input

第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L≥1 且 N≥M≥0。

接下来 N 行,每行一个整数,第i 行的整数Di​(0<Di​<L), 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

Output

一个整数,即最短跳跃距离的最大值。

Sample 1

InputcopyOutputcopy
25 5 2 
2
11
14
17 
21
4

实现:经典的求最大的最小值问题,设距离,符合不移走,不符合移走,结果小于等于移走数。代码写的很详细。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5;
int a[N];

bool check(int* a, int n, int val, int m,int len);

//设距离,符合不移走,不符合移走,结果小于等于移走数
int main()
{
	int L, n, m;
	cin >> L >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];
	int min = 1, max = L;
	while (min <= max) {
		int mid = (min + max) / 2;
		if (check(a, n, mid, m,L)) min = mid + 1;
		else max = mid - 1;
	}
	if (check(a, n, min, m, L)) cout << min << endl;//最后结果不是min就是max,验证一下即可
	else cout << max << endl;
	return 0;
}

bool check(int* a, int n, int val, int m,int len)
{
	int l = 0;//起点
	int count = 0;//搬运的数量
	for (int i = 1; i <= n; i++) {
		if (a[i] - l < val) count++;
		else {
			l = a[i];
		}
	}
	if (len - a[n] < val) count++;//终点也要比较
	if (count > m) return false;
	else return true;
}

C---Monthly Expense

Farmer John is an astounding accounting wizard and has realized he might run out of money to run the farm. He has already calculated and recorded the exact amount of money (1 ≤ moneyi ≤ 10,000) that he will need to spend each day over the next N (1 ≤ N ≤ 100,000) days.

FJ wants to create a budget for a sequential set of exactly M (1 ≤ M ≤ N) fiscal periods called "fajomonths". Each of these fajomonths contains a set of 1 or more consecutive days. Every day is contained in exactly one fajomonth.

FJ's goal is to arrange the fajomonths so as to minimize the expenses of the fajomonth with the highest spending and thus determine his monthly spending limit.

Input

Line 1: Two space-separated integers: N and M
Lines 2..N+1: Line i+1 contains the number of dollars Farmer John spends on the ith day

Output

Line 1: The smallest possible monthly limit Farmer John can afford to live with.

Sample

InputcopyOutputcopy
7 5
100
400
300
100
500
101
400
500

Hint

If Farmer John schedules the months so that the first two days are a month, the third and fourth are a month, and the last three are their own months, he spends at most $500 in any month. Any other method of scheduling gives a larger minimum monthly limit.

理解:

        这道题目描述了农夫约翰面临的预算问题。他已经计算并记录了未来N天的每天花费金额。现在他想要制定一个包含恰好M个财政期间的预算,称为"fajomonths"。每个"fajomonths"包含一个或多个连续的天数,并且每一天都恰好包含在一个"fajomonths"中。

        约翰的目标是安排这些"fajomonths",以最小化最高花费的"fajomonths"的支出金额,并确定他的月度最低开销限额。

AC代码(求最小的最大值问题)

#include<iostream>
using namespace std;
const int N = 1e5 + 5;
int a[N];

bool check(int* a, int n, int val, int m);

int main()
{
	int n, m;
	cin >> n >> m;
	int max = 0, sum = 0;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
		if (a[i] > max) max = a[i];
		sum += a[i];
	}
	// 使用二分查找算法找到最小的月度支出限额
	while (max <= sum) {
		int mid = (max + sum) / 2;
		if (check(a, n, mid, m)) max = mid + 1;
		else sum = mid - 1;
	}
	cout << max << endl;
	return 0;
}


bool check(int* a, int n, int val, int m)
{
	int sum = 0;
	int count = 0;

	for (int i = 0; i < n; i++) {
		if (val < a[i])// 如果当前支出超过目标值,返回false
			return false;

		if (val - sum >= a[i]) {
			sum += a[i];
		}
		else {
			sum = a[i];
			count++;
		}
	}

	// 检查fajomonth的个数是否不超过允许的个数m
	if (count >= m)
		return true;
	else
		return false;
}

四,前缀与差分

一维前缀(就是序列前n项累加)

例题:

输入一个长度为n的整数序列。
接下来再输入m个询问,每个询问输入一对l, r。
对于每个询问,输出原序列中从第l个数到第r个数的和。

输入格式

第一行包含两个整数n和m。
第二行包含n个整数,表示整数数列。
接下来m行,每行包含两个整数l和r,表示一个询问的区间范围。

输出格式

共m行,每行输出一个询问的结果。


数据范围

1≤l≤r≤n,
1≤n,m≤100000,
−1000≤数列中元素的值≤1000

输入样例:

5 3
2 1 3 6 4
1 2
1 3
2 4

输出样例:

3
6
10

如果用暴力算法,时间复杂度是O(m*n),如果nm的数据量稍微大一点就有可能超时,而我们如果使用前缀和的方法来做的话就能够将时间复杂度降到O(n + m),大大提高了运算效率。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int a[N] = { 0 };

int main()
{
	int n,m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		a[i] = a[i-1] + x;//前缀和
	}
	for (int i = 0; i < m; i++) {
		int l, r;
		cin >> l >> r;
		cout << a[r] - a[l - 1] << endl;;//r和l都包含在内,所以是a[l-1]
	}
	return 0;
}

二维前缀

练习一道完整题目:

输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数x1, y1, x2, y2,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式

第一行包含三个整数n,m,q。

接下来n行,每行包含m个整数,表示整数矩阵。

接下来q行,每行包含四个整数x1, y1, x2, y2,表示一组询问。

输出格式

共q行,每行输出一个询问的结果。

数据范围

1≤n,m≤1000,
1≤q≤200000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤矩阵内元素的值≤1000

  输入样例:

3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4

输出样例:

17
27
21

代码

#include<bits/stdc++.h>
using namespace std;
int a[1005][1005];
int s[1005][1005] = { 0 };//二维前缀和

int main()
{
	int n, m, q;
	cin >> n >> m >> q;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
		}
	}

	//求出每个坐标的二维前缀和
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			s[i][j] = s[i - 1][j] + s[i][j - 1] + a[i][j] - s[i - 1][j - 1];
		}
	}

	for (int i = 0; i < q; i++) {
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;//通过面积法求出答案
	}
	return 0;
}

一维差分

类似于数学中的求导和积分,差分可以看成前缀和的逆运算。

题目练习:

输入一个长度为n的整数序列。
接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c
请你输出进行完所有操作后的序列。

输入格式

第一行包含两个整数n和m。
第二行包含n个整数,表示整数序列。
接下来m行,每行包含三个整数l,r,c,表示一个操作。
输出格式
共一行,包含n个整数,表示最终序列。

数据范围

1≤n,m≤100000,
1≤l≤r≤n,
−1000≤c≤1000,
−1000≤整数序列中元素的值≤1000

输入样例:

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1

 输出样例:

3 4 5 3 4 2

代码:

#include<bits/stdc++.h>
using namespace std;
int a[1005] = { 0 };
int b[1005] = { 0 };

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];

	//求每一项的差分
	for (int i = 1; i <= n; i++) {
		b[i] = a[i] - a[i - 1];
	}

	for (int i = 0; i < m; i++) {
		int l, r, val;
		cin >> l >> r >> val;
		b[l] += val;
		b[r + 1] -= val;//范围是【l,r】,r之后的不受影响
	}

	int sum = 0;
	for (int i = 1; i <= n; i++) {
		sum += b[i];
		cout << sum << " ";
	}
	return 0;
}

主要掌握一维前缀一维差分,查考内容。

题目练习

A---Color the ball

N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?

Input

每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。
当N = 0,输入结束。

Output

每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。

Sample

InputcopyOutputcopy
3
1 1
2 2
3 3
3
1 1
1 2
1 3
0
 
1 1 1
3 2 1 

实现:经典的差分模板题,不多说明。

AC代码

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;

int main()
{
	int n;
	while (cin >> n && n) {
		int l, r;
		int a[N] = { 0 };
		for (int i = 0; i < n; i++) {
			cin >> l >> r;
			a[l] += 1;
			a[r + 1] -= 1;//差分的区间是[l,r],r以后的数不变
		}
		int sum = 0;
		for (int i = 1; i <= n; i++) {
			sum += a[i];
			cout << sum;
			if (i != n) cout << " ";
		}
		cout << endl;
	}
	return 0;
}

B---Complete the Sequence

You probably know those quizzes in Sunday magazines: given the sequence 1, 2, 3, 4, 5, what is the next number? Sometimes it is very easy to answer, sometimes it could be pretty hard. Because these "sequence problems" are very popular, ACM wants to implement them into the "Free Time" section of their new WAP portal.
ACM programmers have noticed that some of the quizzes can be solved by describing the sequence by polynomials. For example, the sequence 1, 2, 3, 4, 5 can be easily understood as a trivial polynomial. The next number is 6. But even more complex sequences, like 1, 2, 4, 7, 11, can be described by a polynomial. In this case, 1/2.n^2-1/2.n+1 can be used. Note that even if the members of the sequence are integers, polynomial coefficients may be any real numbers.

Polynomial is an expression in the following form:

P(n) = aD.n^D+aD-1.n^D-1+...+a1.n+a0

 If aD <> 0, the number D is called a degree of the polynomial. Note that constant function P(n) = C can be considered as polynomial of degree 0, and the zero function P(n) = 0 is usually defined to have degree -1.

Input

There is a single positive integer T on the first line of input. It stands for the number of test cases to follow. Each test case consists of two lines. First line of each test case contains two integer numbers S and C separated by a single space, 1 <= S < 100, 1 <= C < 100, (S+C) <= 100. The first number, S, stands for the length of the given sequence, the second number, C is the amount of numbers you are to find to complete the sequence.

The second line of each test case contains S integer numbers X1, X2, ... XS separated by a space. These numbers form the given sequence. The sequence can always be described by a polynomial P(n) such that for every i, Xi = P(i). Among these polynomials, we can find the polynomial Pmin with the lowest possible degree. This polynomial should be used for completing the sequence.

Output

For every test case, your program must print a single line containing C integer numbers, separated by a space. These numbers are the values completing the sequence according to the polynomial of the lowest possible degree. In other words, you are to print values Pmin(S+1), Pmin(S+2), .... Pmin(S+C).

It is guaranteed that the results Pmin(S+i) will be non-negative and will fit into the standard integer type.

Sample

InputcopyOutputcopy
4
6 3
1 2 3 4 5 6
8 2
1 2 4 7 11 16 22 29
10 2
1 1 1 1 1 1 1 1 1 2
1 10
3 
7 8 9
37 46
11 56
3 3 3 3 3 3 3 3 3 3 

理解:本题大意就是根据前面的数列,找出规律求出后面的数列。

难点:不知道怎么找规律,虽然题目有说明,但还是不懂。实际上就是无限差分,直到最后的数列差分都一样,然后倒推前面的数。

AC代码

#include<iostream>
#include<set>
#include<cmath>
using namespace std;
const int N = 1e6 + 5;

int main()
{
	int T;
	cin >> T;
	while (T--) {
		int n, m;
		cin >> n >> m;
		int a[105][105] = { 0 };
		for (int i = 0; i < n; i++) cin >> a[0][i];

		//差分
		for (int i = 1; i <= n - 1; i++) {
			for (int j = 0; j < n - i; j++) {
				a[i][j] = a[i - 1][j+1] - a[i - 1][j];
			}
		}

		//插入新序列
		for (int i = 1; i <= m; i++) {
			a[n - 1][i] = a[n - 1][0];
		}

		//倒推回去,求出原序列
		for (int i = n - 2; i >= 0; i--) {
			for (int j = n-i; j < m+n; j++) {
				a[i][j] = a[i][j - 1] + a[i + 1][j - 1];
			}
		}
		
		for (int i = n; i < m + n; i++) {
			cout << a[0][i];
			cout << " ";
		}
		cout << endl;
	}
	return 0;
}

C---Tallest Cow

FJ's N (1 ≤ N ≤ 10,000) cows conveniently indexed 1..N are standing in a line. Each cow has a positive integer height (which is a bit of secret). You are told only the height H (1 ≤ H ≤ 1,000,000) of the tallest cow along with the index I of that cow.

FJ has made a list of R (0 ≤ R ≤ 10,000) lines of the form "cow 17 sees cow 34". This means that cow 34 is at least as tall as cow 17, and that every cow between 17 and 34 has a height that is strictly smaller than that of cow 17.

For each cow from 1..N, determine its maximum possible height, such that all of the information given is still correct. It is guaranteed that it is possible to satisfy all the constraints.

Input

Line 1: Four space-separated integers: N, I, H and R
Lines 2..R+1: Two distinct space-separated integers A and B (1 ≤ A, BN), indicating that cow A can see cow B.

Output

Lines 1..N: Line i contains the maximum possible height of cow i.

Sample

InputcopyOutputcopy
9 3 5 5
1 3
5 3
4 3
3 7
9 8
5
4
5
3
4
4
5
5
5

理解:有N头牛,每次给出两头牛,这两头牛高度相同,中间的高度两端低,求出牛的最大可能高度。

AC代码

#include<iostream>
#include<set>
using namespace std;
const int N = 1e5 + 5;
long long b[N] = { 0 };
set< pair<int, int> >s;

int main()
{
	int n, c, h, m;
	cin >> n >> c >> h >> m;
	for (int i = 0; i < m; i++) {
		int l, r;
		cin >> l >> r;
		if (l > r) swap(l, r);
		if (s.count({ l,r })) continue;//如果之前做过判断,则不用再执行
		s.insert({ l,r });
		b[l + 1] -= 1;//差分
		b[r] += 1;
	}
	for (int i = 1; i <= n; i++) {
		b[i] = b[i] + b[i - 1];
		cout << b[i] + h << endl;
	}
	return 0;
}

D---IncDec Sequence

给定一个长度为 nn 的数列 a1,a2,⋯ ,ana1​,a2​,⋯,an​,每次可以选择一个区间[l,r][l,r],使这个区间内的数都加 11 或者都减 11。

请问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。

Input

第一行一个正整数 n
接下来 nn 行,每行一个整数,第 i+1i+1行的整数表示 ai。

Output

第一行输出最少操作次数
第二行输出最终能得到多少种结果

Sample 1

InputcopyOutputcopy
4
1
1
2
2
1
2

Hint

对于 100%的数据,n≤100000,0≤ai≤2^31

AC代码

#include<iostream>
#include<set>
#include<cmath>
using namespace std;
const int N = 1e6 + 5;
long long a[N] = { 0 };
long long b[N] = { 0 };


int main()
{
	int n;
	long long count1 = 0, count2 = 0;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) {
		b[i] = a[i] - a[i - 1];
		if (i != 1 && b[i] > 0) count1 += b[i];//记录差分大于0
		else if (i != 1 && b[i] < 0) count2 -= b[i];//记录差分小于0
	}

	long long ans1 = min(count1, count2) + fabs(count1 - count2);//正数负数一一配对,剩下的就只能一步一步加
	long long ans2 = fabs(count1 - count2) + 1;//其他情况加上自己本身的一种情况
	cout << ans1 << endl << ans2 << endl;
	return 0;
}

五,倍增法与ST算法

模板题:

给定一个长度为 N 的数列,和 M次询问,求出每一次询问的区间内数字的最大值。

Input

第一行包含两个整数 N,M分别表示数列的长度和询问的个数。

第二行包含 N 个整数(记为 ai​),依次表示数列的第 i 项。

接下来 M 行,每行包含两个整数 li,rili​,ri​,表示查询的区间为[li​,ri​]。

Output

输出包含 M 行,每行一个整数,依次表示每一次询问的结果。

Sample 1

InputcopyOutputcopy
8 8
9 3 1 7 5 6 0 8
1 6
1 5
2 7
2 6
1 8
4 8
3 7
1 8
9
9
7
7
9
8
7
9

Hint

对于 30%的数据,满足 1≤N,M≤10

对于 70% 的数据,满足 1≤N,M≤10^5

对于 100%的数据,满足 1≤N≤10^5,1≤M≤2×10^6,ai​∈[0,10^9],1≤li≤ri≤N。

AC代码

#include<iostream>
using namespace std;
const int N = 1e6 + 5;
int a[N][20];//a[起点][区间长度]

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i][0];

	//构建ST表
	for (int j = 1; j <= log2(n); j++) {//枚举区间的长度
		for (int i = 1; i + (1 << j) - 1 <= n; i++) {//枚举区间起点,i+(1<<j)-1 相当于 i+2^j-1 
			a[i][j] = max(a[i][j - 1], a[i + (1 << (j - 1))][j - 1]);//预处理
		}
	}

	for (int i = 0; i < m; i++) {
		int l, r;
		cin >> l >> r;
		int k = log2(r - l + 1);//k为区间长度指数 
		cout << max(a[l][k], a[r - (1 << k) + 1][k]) << endl;//这里最好用printf()输出,效率更高
																//通过区间长度,用两端重叠拼凑,得出最值 
	}
	return 0;
}

B站视频讲解:【35 ST表 RMQ问题】 https://www.bilibili.com/video/BV1Sj411o7jp/?share_source=copy_web

题目练习

A---Balanced Lineup G

每天,农夫 John 的 n(1≤n≤5×104)n(1≤n≤5×104) 头牛总是按同一序列排队。

有一天, John 决定让一些牛们玩一场飞盘比赛。他准备找一群在队列中位置连续的牛来进行比赛。但是为了避免水平悬殊,牛的身高不应该相差太大。John 准备了 q(1≤q≤1.8×105)q(1≤q≤1.8×105) 个可能的牛的选择和所有牛的身高 hi(1≤hi≤106,1≤i≤n)hi​(1≤hi​≤106,1≤i≤n)。他想知道每一组里面最高和最低的牛的身高差。

Input

第一行两个数 n,qn,q。

接下来 nn 行,每行一个数 hihi​。

再接下来 qq 行,每行两个整数 aa 和 bb,表示询问第 aa 头牛到第 bb 头牛里的最高和最低的牛的身高差。

Output

输出共 qq 行,对于每一组询问,输出每一组中最高和最低的牛的身高差。

Sample 1

InputcopyOutputcopy
6 3
1
7
3
4
2
5
1 5
4 6
2 2
6
3
0

实现:用两个数列,分别通过ST表求最大值和最小值,最后相减即可。

AC代码

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int a[N][30];
int b[N][30];//两个数组,一个求最大值,一个求最小值

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i][0]);
		b[i][0] = a[i][0];
	}

	//构建ST表
	for (int j = 1; j <= log2(n); j++) {
		for (int i = 1; i + (1 << j) - 1 <= n; i++) {
			a[i][j] = max(a[i][j - 1], a[i + (1 << (j - 1))][j - 1]);
			b[i][j] = min(b[i][j - 1], b[i + (1 << (j - 1))][j - 1]);
		}
	}

	//查询输出
	for (int i = 0; i < m; i++) {
		int l, r;
		cin >> l >> r;
		int k = log2(r - l + 1);
		printf("%d\n", max(a[l][k], a[r - (1 << k) + 1][k]) - min(b[l][k], b[r - (1 << k) + 1][k]));
	}
	return 0;
}

六,排序(快速排序和归并排序)

(1)归并排序

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
long long a[N];
long long b[N];

void merge_sort(int l, int r);
void merge(int l, int r, int mid);

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i];
	merge_sort(1, n);
	for (int i = 1; i <= n; i++) cout << a[i] << " ";
}

void merge_sort(int l, int r)
{
	if (l >= r) return;
	else{
		int mid = (l + r) / 2;
		merge_sort(l, mid);
		merge_sort(mid + 1, r);//不断差分

		merge(l, r, mid);//两个区间合并,并排序。
	}
}

void merge(int l, int r, int mid)
{
	int i = l, j = mid + 1, t = l;//通过双指针将两个区间合入一个数组
	while (i <= mid && j <= r) {
		if (a[i] > a[j]) b[t++] = a[j++];
		else b[t++] = a[i++];
	}
	while (i <= mid) b[t++] = a[i++];
	while (j <= r) b[t++] = a[j++];

	for (int i = l; i < t; i++) a[i] = b[i];
	return;
}

(2)快速排序

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
long long a[N];
long long b[N];

void quick_sort(int l, int r);

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i];
	quick_sort(1, n);
	for (int i = 1; i <= n; i++) cout << a[i] << " ";
}

void quick_sort(int l, int r)
{
	if (l >= r) return;
	
	int i = l, j = r;
	int base = a[(l+r)/2];//取中间数作为基准数
	do{
		while (a[j] > base && i < j) j--;//在前面找到比中间数大的
		while (a[i] < base && i < j) i++;//在后面找到比中间数小的
		if (i <= j) {
			swap(a[i], a[j]);
			i++; j--;
		}
	} while (i <= j);

	if (l < j) quick_sort(l, j);//再对前一部分进行排序的操作
	if (i < r) quick_sort(i, r);//对后面的部分进行操作
	return;
}

题目练习

A---逆序对

猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。

最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>ajai​>aj​ 且 i<ji<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。

Input

第一行,一个数 n,表示序列中有 n个数。

第二行 nn 个数,表示给定的序列。序列中每个数字不超过 10^9。

Output

输出序列中逆序对的数目。

Sample 1

InputcopyOutputcopy
6
5 4 2 6 3 1
11

Hint

对于 25% 的数据,n≤2500

对于 50%50% 的数据,n≤4×10^4

对于所有数据,n≤5×10^5

请使用较快的输入输出

应该不会 O(n2) 过 50 万吧 by chen_zhe

AC代码

#include <bits/stdc++.h>
using namespace std;
int n, a[5000001], b[5000001];
long long ans;
inline void msort(int l, int r)//归并排序
{
	int mid = (l + r) / 2;//取中间 
	if (l == r)//若l == r了,就代表这个子序列就只剩1个元素了,需要返回 
	{
		return;
	}
	else
	{
		msort(l, mid);//分成l和中间一段,中间 + 1和r一段(二分) 
		msort(mid + 1, r);
	}
	int i = l;//i从l开始,到mid,因为现在排序的是l ~ r的区间且要二分合并 
	int j = mid + 1;//j从mid + 1开始,到r原因同上
	int t = l;//数组b的下标,数组b存的是l ~ r区间排完序的值 
	while (i <= mid && j <= r)//同上i,j的解释 
	{
		if (a[i] > a[j])//如果前面的元素比后面大(l ~ mid中的元素 > mid + 1 ~ r中的元素)(逆序对出现!!!) 
		{
			ans += mid - i + 1;//由于l ~ mid和mid + 1 ~ r都是有序序列所以一旦l ~ mid中的元素 > mid + 1 ~ r中的元素而又因为第i个元素 < i + 1 ~ mid那么i + 1 ~ mid的元素都 > 第j个元素。所以+的元素个数就是i ~ mid的元素个数,及mid - i + 1(归并排序里没有这句话,求逆序对里有) 
			b[t++] = a[j++];//第j个元素比i ~ mid的元素都小,那么第j个元素是目前最小的了,就放进b数组里 
			//++j;//下一个元素(mid + 1 ~ r的元素小,所以加第j个元素) 
		}
		else
		{
			b[t++] = a[i++];//i小,存a[i] 
			//++i;//同理 
		}
	}
	while (i <= mid)//把剩的元素(因为较大所以在上面没选) 
	{
		b[t++] = a[i++];//存进去 
		//++i; 
	}
	while (j <= r)//同理 
	{
		b[t++] = a[j++];
		//++j;
	}
	for (register int i = l; i <= r; ++i)//把有序序列b赋值到a里 
	{
		a[i] = b[i];
	}
	return;
}
int main()
{
	scanf("%d", &n);
	for (register int i = 1; i <= n; ++i)
	{
		scanf("%d", &a[i]);
	}
	msort(1, n);//一开始序列是1 ~ n 
	printf("%lld", ans);
	return 0;
}

七,快速幂

模板

#include <bits/stdc++.h>
using namespace std;

long long f(int a, int b);

int main()
{
	int a, b;
	cin >> a >> b;
	cout << f(a, b);
	return 0;
}

long long f(int a, int b)
{
	long long ans=1;
	while (b > 0) {
		if (b % 2 == 1) {//如果指数为奇数
			b -= 1;//把指数减去1,使其变成一个偶数
			ans *= a;//此时记得要把指数为奇数时分离出来的底数的一次方收集好
			b /= 2;//此时指数为偶数,可以继续执行操作
			a *= a;
		}
		else {//如果指数为偶数
			b /= 2;//把指数缩小为一半
			a *= a;
		}
	}
	return ans;
}

简化版

#include <bits/stdc++.h>
using namespace std;

long long f(int a, int b);

int main()
{
	int a, b;
	cin >> a >> b;
	cout << f(a, b);
	return 0;
}

long long f(int a, int b)
{
	long long ans=1;
	while (b > 0) {
		if (b % 2 == 1) {
			ans *= a;
		}
		b /= 2;
		a *= a;
	}
	return ans;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值