蓝桥杯赛前刷题

1. 基础贪心与枚举

1.1 基础贪心

1.1.1 小紫的劣势博弈

B-小紫的劣势博弈_牛客周赛 Round 85

问题与解决方法
  • sort中普通数组用 sort(a+1,a+n+1)

  • 从大到小 : 加greater<int>()

思路:
  • 先排序
  • 然后分别加减
代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n;
int a[N];
int x;

int main()
{
    cin >> n;
    for(int i = 1 ;  i <= n ; i++) cin >> a[i];
    
    sort(a+1 , a+n+1);
    
    
    for(int i = 1 ;  i <= n ; i++)
    {
        if(i % 2 == 1) x += a[i];
        if(i % 2 == 0) x -= a[i];
    }
    
    cout << x;
    
    
    return 0;
}

1.1.2 小梦的AB交换

!洛谷

U535982 C-小梦的AB交换

U535982 C-小梦的AB交换 - 洛谷

题目描述

小梦有一个长度为 2 ∗ n 2 * n 2∗n 的 A B AB AB 串 s s s,即 s s s 中只包含 " A A A" 和 " B B B" 两种字符,且其中恰好有 n n n 个 " A A A" 和 n n n 个 " B B B"。

他可以对 s s s 执行以下操作:

∙ \bullet ∙ 选择 i , j ( 1 ≤ i , j ≤ 2 ⋅ n , i ≠ j ) i, j\ (1 \leq i, j \leq 2\cdot n, i \ne j) i,j (1≤i,j≤2⋅n,i=j),并交换 s i s_i si 和 s j s_j sj。

他想知道,需要至少多少次操作,才能使得 s s s 满足相邻的字符不相同,请你帮他算一算吧。

输入格式

本题有多组测试数据。

输入的第一行包含一个正整数 T T T,表示数据组数。

接下来包含 T T T 组数据,每组数据的格式如下:

第一行一个正整数 n n n,表示 s s s 长度的一半。

第二行一个长度为 2 ∗ n 2*n 2∗n 的字符串 s s s,保证只由 " A A A", " B B B" 两种字符构成。

输出格式

对于每组测试数据:

在单独的一行输出一个整数,表示最少进行的操作次数。

输入输出样例 #1

输入 #1

复制代码
2
3
AAABBB
3
ABAABB

输出 #1

复制代码
1
1

说明/提示

【样例 1 解释】

交换 s 2 = A s_2 = A s2=A 和 s 5 = B s_5=B s5=B,得到 s = s= s= " A B A B A B \rm ABABAB ABABAB",满足题意,一次交换即可。

【数据范围】

令 N N N 表示 T T T 组数据中 n n n 的总和。

对于 50 % \rm 50\% 50% 的数据有: T = 1 , 1 ≤ N ≤ 3 T = 1, 1 \leq N\leq 3 T=1,1≤N≤3。

对于所有的测试数据有: 1 ≤ T ≤ 100 , 1 ≤ N ≤ 10 6 1 \leq T \leq 100, 1 \leq N \leq 10^6 1≤T≤100,1≤N≤106。

问题与解决方法
  • 多思考
  • 注意细节,要考虑到所有情况
  • 多用几个不同的样例测试
思路:
  • 两个一组,分为n组
  • 每组只有"AA" "BB" "AB" " BA"四种情况
  • 每种情况有几个, 记下
  • "AA" 一定等于 "BB" 数(因为'A''B'个数相同)
  • 每个"AA""BB"交换一次即可达到目标
  • "AB""BA" 只有一个时, 不用交换,有多个时,交换""AB""BA"的个数最少的个数" 即可
代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N  = 1e6 + 10;

int n , T;
int a[N];

int main()
{
	cin >> T;
	
	while(T--)
	{
		string s;
		cin >> n >> s;
		
		int x = 0; 
		//AA 1   BB 2   AB 3   BA  4
		
		//存以上四种类型的个数 
		for(int i = 0; i < 2*n; i+=2)
		{
			if(s[i] == 'A')
			{
				if(s[i+1] == s[i])a[1]++;
				else a[3]++;
			}
			else
			{
				if(s[i+1] == s[i])a[2]++;
				else a[4]++;	
			} 
		}
		
		//处理 AA  BB 
		if(a[1] == a[2])
		{
			x+=a[1];
			a[1] = 0;
			a[2] = 0;
		}
		
		
		//处理 AB  BA 
		if(a[3] == a[4])
		{
			x+=a[3];
			a[3] = 0;
			a[4] = 0;
		}
		else
		{
			if(max(a[3], a[4]) != 1) x += min(a[3], a[4]);
			a[3] = 0;
			a[4] = 0;
		}
		
		
		
		cout << x << endl;
	}
	
	return 0;
}

1.1.3 小苯的Z串匹配

C-小苯的Z串匹配_牛客周赛 Round 87

问题与解决方法
  • 一定要注意长度限制, 尽量多用longlong, 或者涉及×+改为/-运算
思路:
  • s[i]> 时,a[i] 必须是正数
  • s[i]< 时,a[i] 必须是负数
  • s[i]= 时,a[i]a[i-1] 必须同号
代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;
typedef long long LL;

LL n, T;
LL a[N];
LL x;

int main()
{
    cin >> T;
    
    while(T--)
    {
        x = 0;
        string s;
        
        cin >> n;
        
        for(int i = 0; i < n; i++) cin >> a[i];
        cin >> s;
        
        for(int i = 0; i < n; i++)
        {
            if(s[i] == '>')
            {
                if(a[i] <= 0)
                {
                    x++;
                    a[i] = 1;
                }
            }
            else if(s[i] == '<') 
            {
                if(a[i] >= 0)
                {
                    x++;
                    a[i] = -1;
                }
            }
            else 
            {
                
                if(a[i] * a[i-1] <= 0) 
                {
                    x++;
                    if(a[i-1] > 0) a[i] = 1;
                    else a[i] = -1;
                }
            }
        }
        
        cout << x << endl; 
    }
    
    return 0;
}

1.2 基础枚举

1.2.1 好数

!洛谷

P10424 [蓝桥杯 2024 省 B] 好数

P10424 [蓝桥杯 2024 省 B] 好数 - 洛谷

题目描述

一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位......)上的数字是奇数,偶数位(十位、千位、十万位......)上的数字是偶数,我们就称之为"好数"。

给定一个正整数 N N N,请计算从 1 1 1 到 N N N 一共有多少个好数。

输入格式

一个整数 N N N。

输出格式

一个整数代表答案。

输入输出样例 #1

输入 #1

复制代码
24

输出 #1

复制代码
7

输入输出样例 #2

输入 #2

复制代码
2024

输出 #2

复制代码
150

说明/提示

样例 1 解释

24 24 24 以内的好数有 1 , 3 , 5 , 7 , 9 , 21 , 23 1,3,5,7,9,21,23 1,3,5,7,9,21,23,一共 7 7 7 个。

数据规模与约定

  • 对于 10 % 10\% 10% 的测试数据, 1 ≤ N ≤ 100 1 \leq N \le 100 1≤N≤100。
  • 对于全部的测试数据, 1 ≤ N ≤ 10 7 1 \le N \leq 10^7 1≤N≤107。
问题与解决方法
思路:
  • 暴力枚举
代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

int N;
int ret;

bool isGood(int n)
{
	int k = 0;
		
	while(n)
	{
		k++;
		if(k%2 == 1 && n%2 == 0)return false;
		if(k%2 == 0 && n%2 == 1)return false;
		
		n/=10;
	}
	
	return true;
}

int main()
{
	cin >> N;
	for(int i = 1; i <= N ; i++)
	{
		
		if(isGood(i)) ret++; 
	}
	
	cout << ret;
	
	return 0;
}

1.2.2 小红杀怪

D-小红杀怪_2024BistuACM萌新练习赛01

问题与解决方法
  • 输出 0-10的随机数
cpp 复制代码
cout << rand()%10 << endl;
  • 向上取整 (a/x)
cpp 复制代码
(a + x - 1) / x
思路:
  • 暴力枚举所有情况
代码:
  • 贪心思路 但只过了80%
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

int a, b, x, y, aa, bb; 
int num, num2, num3;

int main()
{
	cin >> a >> b >> x >> y;
	
	if(x>y)
	{
		num += a/x;
		a = a%x;
		num += b/x;
		b = b%x;
		
		aa = a;
		bb = b;
		num2 = 0;
		while(aa>0)
		{
			aa -= x;
			num2++;
		}
		while(bb>0)
		{
			bb -= x;
			num2++;
		}
			
		num3 = 0;
		while(a>0 || b>0)
		{
			a -= y;
			b -= y;
			num3++;
		}
		
		num += min(num2, num3);
		
	}
	else
	{
		num += min(a,b)/y;
		a = a%y;
		b = b%y;
		
		
		aa = a;
		bb = b;
		num2 = 0;
		while(aa>0)
		{
			aa -= x;
			num2++;
		}
		while(bb>0)
		{
			bb -= x;
			num2++;
		}
			
		num3 = 0;
		while(a>0 || b>0)
		{
			a -= y;
			b -= y;
			num3++;
		}
		
		num += min(num2, num3);
		
	}
	
	cout << num;
	
	return 0;
 } 
  • 枚举
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

int a, b, x, y, aa, bb; 
int num;
int ret = 1e8;

int main()
{
	cin >> a >> b >> x >> y;
	
	for(int i = 0 ; i <= (max(a,b)+y-1)/y; i++) 
	{
		//初始化 
		num = 0;
		aa = a;
		bb = b; 
		
		//群伤 
		num += i; 
		aa -= i*y;
		bb -= i*y;
		
		//单伤
		num += (aa>0) ? (aa + x - 1) / x : 0;
		num += (bb>0) ? (bb + x - 1) / x : 0;
		
		//记录最小值 
		ret = min(ret,num);
	}
	
	cout << ret;
	
	return 0;
 } 

1.2.3 训练士兵

!洛谷

P10387 [蓝桥杯 2024 省 A] 训练士兵

P10387 [蓝桥杯 2024 省 A] 训练士兵 - 洛谷

题目描述

在蓝桥王国中,有 n n n 名士兵,这些士兵需要接受一系列特殊的训练,以提升他们的战斗技能。对于第 i i i 名士兵来说,进行一次训练所需的成本为 p i p_i pi 枚金币,而要想成为顶尖战士,他至少需要进行 c i c_i ci 次训练。

为了确保训练的高效性,王国推出了一种组团训练的方案。该方案包含每位士兵所需的一次训练,且总共只需支付 S S S 枚金币(组团训练方案可以多次购买,即士兵可以进行多次组团训练)。

作为训练指挥官,请你计算出最少需要花费多少金币,才能使得所有的士兵都成为顶尖战士?

输入格式

输入的第一行包含两个整数 n n n 和 S ,用一个空格分隔,表示士兵的数量和进行一次组团训练所需的金币数。

接下来的 n n n 行,每行包含两个整数 p i p_i pi 和 c i c_i ci,用一个空格分隔,表示第 i i i 名士兵进行一次训练的金币成本和要成为顶尖战士所需的训练次数。

输出格式

输出一行包含一个整数,表示使所有士兵成为顶尖战士所需的最少金币数。

输入输出样例 #1

输入 #1

复制代码
3 6
5 2
2 4
3 2

输出 #1

复制代码
16

说明/提示

花费金币最少的训练方式为:进行 2 2 2 次组团训练,花费 2 × 6 = 12 2 × 6 = 12 2×6=12 枚金币,此时士兵 1 , 3 1, 3 1,3 已成为顶尖战士;再花费 4 4 4 枚金币,让士兵 2 2 2 进行两次训练,成为顶尖战士。总花费为 12 + 4 = 16 12 + 4 = 16 12+4=16。

对于 40 % 40\% 40% 的评测用例, 1 ≤ n ≤ 10 3 , 1 ≤ p i , c i ≤ 10 5 , 1 ≤ S ≤ 10 7 1 ≤ n ≤ 10^3,1 ≤ p_i , c_i ≤ 10^5,1 ≤ S ≤ 10^7 1≤n≤103,1≤pi,ci≤105,1≤S≤107。

对于所有评测用例, 1 ≤ n ≤ 10 5 , 1 ≤ p i , c i ≤ 10 6 , 1 ≤ S ≤ 10 10 1 ≤ n ≤ 10^5,1 ≤ p_i , c_i ≤ 10^6,1 ≤ S ≤ 10^{10} 1≤n≤105,1≤pi,ci≤106,1≤S≤1010。

问题与解决方法
  • 注意训练次数不能为负
cpp 复制代码
num += p[j] * ((c[j] - i)>0 ? (c[j] - i) : 0);
思路:
代码:
  • 枚举做法 会超时
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

long long p[N], c[N];
long long  n, S;
long long maxc = -1;
long long  num, ret = 1e17;

int main()
{
	scanf("%lld %lld", &n , &S);
	
	for(int i = 1; i<= n; i++)
	{
		scanf("%lld %lld", &p[i] , &c[i]);
		maxc = max(maxc, c[i]);
	}
	
	
	for(int i = 0; i<= maxc; i++)
	{
		//初始化 
		num = 0;
		
		//团练 
		num += i*S;
		
		//单练
		for(int j = 1; j <= n; j++)
		{
			num += p[j] * ((c[j] - i)>0 ? (c[j] - i) : 0);
			 
		} 
		
		
		ret = min(ret, num);
		
	}
	
	printf("%lld", ret);
	
	return 0;
 } 
  • 贪心
cpp 复制代码

2. 前缀和

小红的陡峭值(三)(hard)

D-小红的陡峭值(三)(hard)_牛客周赛 Round 84

思路:

  • 前缀和

代码:

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

typedef long long LL;

LL n, k;
string s; 
LL a[N];
LL sum;

int main()
{
	//优化输入输出 
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	//输入数据 
	cin >> n >> k;
	cin >> s;
	
	//构造前缀和数组 
	for(int i = 1; i < s.size(); i++) a[i] = abs(s[i] - s[i-1]) + a[i-1];
	
	//加子段和 
	for(int i = k-1; i < n; i++) sum += a[i] - a[i-k+1];
	
	//输出 
	cout << sum;
	
	return 0;
}

3. 二进制

小苯的异或疑惑(hard)

M-小苯的异或疑惑(hard)_北京信息科技大学第十五届程序设计竞赛(同步赛)

思路:

异或运算有一个性质:一个数异或偶数次等于 0,异或奇数次等于它本身

我们需要分析在最终的答案 ans = f(1,2) ^ f(1,3) ^ ... ^ f(n-1,n) 中,原数组中的每一个元素 a i a_i ai 到底被异或了多少次。

  1. 分析贡献次数

    对于数组中的某一个元素 a i a_i ai,它会在哪些 f ( i , j ) f(i, j) f(i,j) 中出现?

    • 当 i i i 作为第一个下标时: f ( i , i + 1 ) , f ( i , i + 2 ) , ... , f ( i , n ) f(i, i+1), f(i, i+2), \dots, f(i, n) f(i,i+1),f(i,i+2),...,f(i,n)。这种情况共有 ( n − i ) (n-i) (n−i) 次。
    • 当 i i i 作为第二个下标时: f ( 1 , i ) , f ( 2 , i ) , ... , f ( i − 1 , i ) f(1, i), f(2, i), \dots, f(i-1, i) f(1,i),f(2,i),...,f(i−1,i)。这种情况共有 ( i − 1 ) (i-1) (i−1) 次。
      所以, a i a_i ai 总共出现的次数为: ( n − i ) + ( i − 1 ) = n − 1 (n-i) + (i-1) = n-1 (n−i)+(i−1)=n−1 次。
  2. 根据奇偶性判断

    • 如果 n − 1 n-1 n−1 是偶数 ,那么 a i a_i ai 在最终结果中被异或了偶数次,结果为 0,对答案没有贡献。
    • 如果 n − 1 n-1 n−1 是奇数 ,那么 a i a_i ai 在最终结果中被异或了奇数次,相当于 a i a_i ai 本身,对答案的贡献就是 a i a_i ai。
  3. 结论

    • n n n 为奇数 时, n − 1 n-1 n−1 是偶数。所有数的贡献都抵消了,答案为 0
    • n n n 为偶数 时, n − 1 n-1 n−1 是奇数。所有数都会贡献一次,答案为 所有 a i a_i ai 的异或和

代码:

  • 暴力 会超时
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 2e5 + 10;

LL n;
LL ret;
LL a[N];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];
	
	for(int i = 1; i < n; i++)
	{
		for(int j = i+1; j <= n; j++)
		{
			ret = ret^a[i]^a[j]; 
		}
	}
	
	cout << ret;
	
	return 0;
 } 
  • 正确做法
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 2e5 + 10;

LL n;
LL ret;
LL a[N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    cin >> n;
    
    // 如果 n 是奇数,每个数出现 n-1 (偶数) 次,异或结果为 0
    // 如果 n 是偶数,每个数出现 n-1 (奇数) 次,异或结果为所有数的异或和
    if (n % 2 == 0) 
	{
        for(int i = 1; i <= n; i++) 
		{
            cin >> a[i];
            ret ^= a[i];
        }
    } 
	else 
	{
       
        for(int i = 1; i <= n; i++) 
		{
            cin >> a[i];
        }
        ret = 0;
    }

    cout << ret;
    
    return 0;
}

4. 洛谷题单

4.1 A-B 数对

!洛谷

P1102 A-B 数对

P1102 A-B 数对 - 洛谷

题目背景

出题是一件痛苦的事情!

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

题目描述

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

输入格式

输入共两行。

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

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

输出格式

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

输入输出样例 #1

输入 #1

复制代码
4 1
1 1 2 3

输出 #1

复制代码
3

说明/提示

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

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 2 × 10 5 1 \leq N \leq 2 \times 10^5 1≤N≤2×105, 0 ≤ a i < 2 30 0 \leq a_i <2^{30} 0≤ai<230, 1 ≤ C < 2 30 1 \leq C < 2^{30} 1≤C<230。

2017/4/29 新添数据两组

思路:

代码:

  • 暴力 -> 3个测试点超时
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	long long n, c;
	
	cin >> n >> c;
	
	long long a[n];
	long long ret = 0;
	 
	for(long long i = 0; i < n; i++) cin >> a[i];
	
	sort(a,a+n,greater<int>());
	
//	for(long long i = 0; i < n; i++) cout << a[i] << " " ; 
//	cout << endl; 
	
	for(long long i = 0; i < n-1; i++)
	{
		for(long long j = i+1; j < n; j++)
		{
			if(a[i]-a[j] == c) ret++;
//			cout << endl << "a[i]=" << a[i] << endl << "a[j]=" << a[j] << endl;
//			cout <<  a[i]-a[j] << endl;
		}
	}
	
	cout << ret;
	 
	return 0;
 } 
  • 用map
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
	LL n, c;
	cin >> n >> c;
	
	map<LL,LL> m;
	vector<LL>a(n,0);
	
	for(LL i = 0 ; i < n; i++)
	{
		cin >> a[i];
		m[a[i]]++;
	}
	
	LL ret = 0;
	
	for(LL i = 0; i < n; i++)
	{
		LL t = a[i] + c;
		if(m.find(t) != m.end())
		{
			ret += m[t];
		}
	}
    
    cout << ret;
    
    return 0;
}

!洛谷

4.2 保龄球

P1918 保龄球

题目描述

DL 算缘分算得很烦闷,所以常常到体育馆去打保龄球解闷。因为他保龄球已经打了几十年了,所以技术上不成问题,于是他就想玩点新花招。

DL 的视力真的很不错,竟然能够数清楚在他前方十米左右每个位置的瓶子的数量。他突然发现这是一个炫耀自己好视力的借口------他看清远方瓶子的个数后从某个位置发球,这样就能打倒一定数量的瓶子。

  1. ◯ ◯ ◯ \bigcirc \bigcirc \bigcirc ◯◯◯

  2. ◯ ◯ ◯ ◯ \bigcirc \bigcirc \bigcirc\ \bigcirc ◯◯◯ ◯

  3. ◯ \bigcirc ◯

  4. ◯ ◯ \bigcirc\ \bigcirc ◯ ◯

如上图,每个 " ◯ \bigcirc ◯" 代表一个瓶子。如果 DL 想要打倒 3 3 3 个瓶子就在 1 1 1 位置发球,想要打倒 4 4 4 个瓶子就在 2 2 2 位置发球。

现在他想要打倒 m m m 个瓶子。他告诉你每个位置的瓶子数,请你给他一个发球位置。

输入格式

第一行包含一个正整数 n n n,表示位置数。

第二行包含 n n n 个正整数 a i a_i ai ,表示第 i i i 个位置的瓶子数,保证各个位置的瓶子数不同。

第三行包含一个正整数 Q Q Q,表示 DL 发球的次数。

第四行至文件末尾,每行包含一个正整数 m m m,表示 DL 需要打倒 m m m 个瓶子。

输出格式

共 Q Q Q 行。每行包含一个整数,第 i i i 行的整数表示 DL 第 i i i 次的发球位置。若无解,则输出 0 0 0。

输入输出样例 #1

输入 #1

复制代码
5
1 2 4 3 5
2
4
7

输出 #1

复制代码
3
0

说明/提示

【数据范围】

对于 50 % 50\% 50% 的数据, 1 ≤ n , Q ≤ 1000 , 1 ≤ a i , m ≤ 10 5 1 \leq n, Q \leq 1000, 1 \leq a_i, m \leq 10^5 1≤n,Q≤1000,1≤ai,m≤105。

对于 100 % 100\% 100% 的数据, 1 ≤ n , Q ≤ 100000 , 1 ≤ a i , m ≤ 10 9 1 \leq n,Q \leq 100000, 1 \leq a_i, m \leq 10^9 1≤n,Q≤100000,1≤ai,m≤109。

问题

  • map的find找的是第一个元素
  • ->first -> second

代码:

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	ll n;
	cin >> n;
	
	map<ll,ll> mm;
	ll a;
	
	for(int i = 0; i < n; i++)
	{
		cin >> a;
		mm[a] = i;
	}
	 
	ll q, m;
	cin >> q;
	
	
	while(q--)
	{
		cin >> m;
		if(mm.find(m) != mm.end())
		{
			auto it = mm.find(m); 
			cout << (it -> second) + 1 << endl;
		}
		else
		{
			cout << "0" << endl;
		}
	 } 
	
	return 0;
 } 

4.3 学籍管理

!洛谷

P5266 【深基17.例6】学籍管理

P5266 【深基17.例6】学籍管理 - 洛谷

题目描述

您要设计一个学籍管理系统,最开始学籍数据是空的,然后该系统能够支持下面的操作(不超过 10 5 10^5 105 条):

  • 插入与修改,格式 1 NAME SCORE:在系统中插入姓名为 NAME \texttt{NAME} NAME(由字母和数字组成不超过 20 20 20 个字符的字符串,区分大小写),分数为 SCORE \texttt{SCORE} SCORE( 0 < SCORE < 2 31 0<\texttt{SCORE}<2^{31} 0<SCORE<231) 的学生。如果已经有同名的学生则更新这名学生的成绩为 SCORE \texttt{SCORE} SCORE。如果成功插入或者修改则输出 OK
  • 查询,格式 2 NAME:在系统中查询姓名为 NAME \texttt{NAME} NAME 的学生的成绩。如果没能找到这名学生则输出 Not found,否则输出该生成绩。
  • 删除,格式 3 NAME:在系统中删除姓名为 NAME \texttt{NAME} NAME 的学生信息。如果没能找到这名学生则输出 Not found,否则输出 Deleted successfully
  • 汇总,格式 4:输出系统中学生数量。

输入格式

第一行,输入一个正整数 Q Q Q( 1 ≤ Q ≤ 10 5 1 \le Q \le 10^5 1≤Q≤105),表示操作数量。

接下来 Q Q Q 行,每行先输入一个正整数 o p op op( o p ∈ [ 1 , 4 ] op \in [1,4] op∈[1,4]),表示操作种类。接着:

  • 如果 o p = 1 op = 1 op=1,则再输入一个字符串 NAME \texttt{NAME} NAME 以及一个正整数 SCORE \texttt{SCORE} SCORE,含义见题目描述。
  • 如果 o p = 2 op = 2 op=2,则再输入一个字符串 NAME \texttt{NAME} NAME,含义见题目描述。
  • 如果 o p = 3 op = 3 op=3,则再输入一个字符串 NAME \texttt{NAME} NAME,含义见题目描述。
  • 如果 o p = 4 op = 4 op=4,则无需再输入其他内容。

输出格式

共输出 Q Q Q 行,每行输出一个字符串或正整数,为对应操作的处理结果,具体含义见题目描述。

输入输出样例 #1

输入 #1

复制代码
5
1 lxl 10
2 lxl
3 lxl
2 lxl
4

输出 #1

复制代码
OK
10
Deleted successfully
Not found
0
  • map应用

代码:

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

ll q, op;
map<string,ll> m;
string s;
ll score;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	cin >> q;
	
	while(q--)
	{
		cin >> op;
		
		switch(op)
		{
			case 1:
				
				cin >> s >> score;
				m[s] = score;
				cout << "OK" << "\n";
				break;
				
			case 2:
				
				cin >> s;
				if(m.find(s) != m.end())
				{
					cout << m[s] << "\n";
				}
				else
				{
					cout << "Not found" << "\n";
				}
				break;
				
			case 3:
				
				cin >> s;
				if(m.find(s) != m.end())
				{
					m.erase(s);
					cout << "Deleted successfully" << "\n";
				}
				else
				{
					cout << "Not found" << "\n";
				}
				
				break;
				
			case 4:
				
				cout << m.size() << endl;
			
				break;	
				
		 } 
	}
	
	return 0;
 } 

4.4 木材仓库

!洛谷

P5250 【深基17.例5】木材仓库

P5250 【深基17.例5】木材仓库 - 洛谷

题目描述

博艾市有一个木材仓库,里面可以存储各种长度的木材,但是保证没有两个木材的长度是相同的。作为仓库负责人,你有时候会进货,有时候会出货,因此需要维护这个库存。有不超过 10 5 10^5 105 条的操作:

  • 进货,格式 1 Length:在仓库中放入一根长度为 L e n g t h Length Length(不超过 10 9 10^9 109)的木材。如果已经有相同长度的木材那么输出 Already Exist
  • 出货,格式 2 Length:从仓库中取出长度为 L e n g t h Length Length 的木材。如果没有刚好长度的木材,取出仓库中存在的和要求长度最接近的木材。如果有多根木材符合要求,取出比较短的一根。输出取出的木材长度。如果仓库是空的,输出 Empty

输入格式

第一行一个数 m m m 代表操作次数。

接下来 m m m 行,每行一次操作,格式如题目描述所示。

输出格式

对于每次操作,按照题目描述要求输出答案。

输入输出样例 #1

输入 #1

复制代码
7
1 1
1 5
1 3
2 3
2 3
2 3
2 3

输出 #1

复制代码
3
1
5
Empty

问题

  • m->first 要先赋值给其他,再运算
  • lower_bound与upper_bound的使用
  • 所有情况都要考虑到

代码:

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

ll n, op;
map<ll,ll> m;
ll l;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	cin >> n;
	
	while(n--)
	{
		cin >> op;
		
		switch(op)
		{
			case 1:
				
				cin >> l;
				
				if(m.find(l) != m.end())
				{
					cout << "Already Exist" << "\n";
				} 
				else
				{
					m[l]++;
				}
				
				break;
				
			case 2:
				
				cin >> l;
				
				if(m.empty())
				{
					cout << "Empty" << "\n";
					break; 
				}
				
				auto it = m.lower_bound(l); // 第一个 >= l 的
				
				// 情况1:l 比所有元素都大 → it == m.end()
				if(it == m.end())
				{
					auto it3 = prev(m.end()); // 最后一个元素(最大)
					cout << it3->first << "\n";
					m.erase(it3->first);
					break;
				}
				
				// 情况2:存在等于 l 的
				if(it->first == l)
				{
					cout << l << "\n";
					m.erase(l);
					break;
				}
				
				// 情况3:l 比所有元素都小 → it == m.begin()
				if(it == m.begin())
				{
					cout << it->first << "\n";
					m.erase(it->first);
					break;
				}
				
				// 情况4:l 在中间,有左右邻居
				auto it2 = prev(it); // 左邻居(< l)
				ll left_val = it2->first;
				ll right_val = it->first;
				
				ll dist_left = l - left_val;
				ll dist_right = right_val - l;
				
				if(dist_left < dist_right)
				{
					cout << left_val << "\n";
					m.erase(left_val);
				}
				else if(dist_left > dist_right)
				{
					cout << right_val << "\n";
					m.erase(right_val);
				}
				else // 距离相等,选较短的(即 left_val)
				{
					cout << left_val << "\n";
					m.erase(left_val);
				}
				break;
				 	
		}
	}
	
	return 0; 
 } 

4.5 小梦的AB交换

  • 见1.1.2

4.6 求区间和

!洛谷

B3612 【深进1.例1】求区间和

B3612 【深进1.例1】求区间和 - 洛谷

题目描述

给定 n n n 个正整数组成的数列 a 1 , a 2 , ⋯   , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an 和 m m m 个区间 [ l i , r i ] [l_i,r_i] [li,ri],分别求这 m m m 个区间的区间和。

输入格式

第一行包含一个正整数 n n n,表示序列的长度。

第二行包含 n n n 个正整数 a 1 , a 2 , ⋯   , a n a_1,a_2, \cdots ,a_n a1,a2,⋯,an。

第三行包含一个正整数 m m m,表示区间的数量。

接下来 m m m 行,每行包含两个正整数 l i , r i l_i,r_i li,ri,满足 1 ≤ l i ≤ r i ≤ n 1\le l_i\le r_i\le n 1≤li≤ri≤n。

输出格式

共 m m m 行,其中第 i i i 行包含一个正整数,表示第 i i i 组答案的询问。

输入输出样例 #1

输入 #1

复制代码
4
4 3 2 1
2
1 4
2 3

输出 #1

复制代码
10
5

说明/提示

样例解释

第 1 1 1 到第 4 4 4 个数加起来和为 10 10 10。第 2 2 2 个数到第 3 3 3 个数加起来和为 5 5 5。

数据范围

对于 50 % 50 \% 50% 的数据: n , m ≤ 1000 n,m\le 1000 n,m≤1000;

对于 100 % 100 \% 100% 的数据: 1 ≤ n , m ≤ 10 5 1 \le n, m\le 10^5 1≤n,m≤105, 1 ≤ a i ≤ 10 4 1 \le a_i\le 10^4 1≤ai≤104。

思路

简单前缀和

代码:

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const ll N = 1e5+10;

ll n;
ll a[N];
ll m;
ll l,r;
ll b[N];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	cin >> n;
	for(int i = 1; i<= n; i++)cin >> a[i];
	
	for(int i = 1; i<= n; i++)b[i] = b[i-1]+a[i];
	
	cin >> m;
	while(m--)
	{
		cin >> l >> r;
		
		cout << b[r]-b[l-1] << "\n";
	}
	
	return 0;
 } 

4.7 数列前缀和(二维)

!洛谷

B3693 数列前缀和 4

B3693 数列前缀和 4 - 洛谷

题目背景

这次不是数列的问题了。

题目描述

给定一个 n n n 行 m m m 列的矩阵 a a a,有 q q q 次询问,每次给定 ( u , v ) (u, v) (u,v) 和 ( x , y ) (x, y) (x,y),请你求出:

( ∑ i = u x ∑ j = v y a i , j )   m o d   2 64 (\sum_{i = u}^x \sum_{j = v}^y a_{i,j}) \bmod 2^{64} (i=u∑xj=v∑yai,j)mod264

也就是求出以 ( u , v ) (u, v) (u,v) 为左上角、 ( x , y ) (x,y) (x,y) 为右下角的矩形元素和对 2 64 2^{64} 264 取余数的结果。

输入格式

本题单测试点内有多组测试数据

输入的第一行是一个整数 T T T,表示数据组数。接下来依次给出每组数据的输入信息:

第一行三个整数,依次表示矩阵的行数 n n n 和列数 m m m 以及询问数 q q q。

接下来 n n n 行,每行 m m m 个整数。第 i i i 行第 j j j 个整数表示 a i , j a_{i,j} ai,j。

接下来 q q q 行,每行四个整数,依次为 u , v , x , y u,v,x, y u,v,x,y,表示一组询问。

输出格式

为了避免输出过大,对于每组数据,请输出一行一个整数,表示本组数据的所有询问的答案的按位异或和。

输入输出样例 #1

输入 #1

复制代码
2
3 3 3
1 2 3
4 5 6
7 8 9
1 1 3 3
2 1 2 2
1 2 2 3
2 2 1
1 3
4 6
2 2 2 2

输出 #1

复制代码
52
6

说明/提示

样例 1 解释

对第一组数据,三次询问的答案依次为 45 , 9 , 16 45,9,16 45,9,16。其按位异或和为 52 52 52。

数据规模与约定

对全部的测试点,保证 1 ≤ T ≤ 10 1 \leq T \leq 10 1≤T≤10, 1 ≤ n , m ≤ 10 3 1 \leq n, m \leq 10^3 1≤n,m≤103, 1 ≤ q ≤ 10 6 1 \leq q \leq 10^6 1≤q≤106, 0 ≤ a i < 2 64 0 \leq a_i < 2^{64} 0≤ai<264, 1 ≤ u ≤ x ≤ n 1 \leq u \leq x \leq n 1≤u≤x≤n, 1 ≤ v ≤ y ≤ m 1 \leq v \leq y \leq m 1≤v≤y≤m。

数据保证 ∑ ( n × m ) ≤ 10 6 \sum(n \times m) \leq 10^6 ∑(n×m)≤106, ∑ q ≤ 10 6 \sum q \leq 10^6 ∑q≤106。即输入矩阵的总大小和询问总数均不超过 10 6 10^6 106。

提示

如果你不知道什么是按位异或和,可以在你的代码里添加如下的函数:

cpp 复制代码
template <class T>
T getXorSum(T *begin, T *end) {
  T ret = 0;
  for (T *it = begin; it != end; ++it) ret ^= *it;
  return ret;
}

这一函数的作用是计算传入数组(包括 std::vector)某一左闭右开区间的按位异或和,返回值类型与传入数组的类型相同,调用方法与 std::sort 类似,例如,要求数组 a a a 的 a 1 ∼ a n a_1 \sim a_n a1∼an 的按位异或和,则调用 getXorSum(a + 1, a + 1 + n),求 a 0 ∼ a n − 1 a_0 \sim a_{n - 1} a0∼an−1 的按位异或和,则调用 getXorSum(a, a + n)。如果 a a a 是 std::vector,则将上述调用代码里的 a 均改为 a.begin() 即可。

问题

  • 数据范围超过 2 64 2^{64} 264 要用 unsigned long long
  • C++ 中的 unsigned long long 类型在进行加减乘运算时,如果结果超过 2 64 2^{64} 264 会自动发生自然溢出(相当于自动对取模)。因此,不需要手动写 % 操作,直接使用 unsigned long long 存储即可
  • 二维前缀和
    • 构造 : b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + a[i][j];
    • 计算 : b[x][y] - b[u-1][y] - b[x][v-1] + b[u-1][v-1];

思路:

二维前缀和

代码:

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e3 + 10;

ll T;
ll n, m, q;
unsigned long long a[N][N]; 
unsigned long long b[N][N];
ll u, v, x, y;
unsigned long long ret; 

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	
	cin >> T;
	while(T--)
	{
		
		cin >> n >> m >> q;
		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= m; j++)
			{
				cin >> a[i][j];//读入矩阵 
				b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + a[i][j];//构造二维前缀和数组 
			}
		}
		
		ret = 0; 
		while(q--)
		{
			cin >> u >> v >> x >> y;
			ret ^= b[x][y] - b[u-1][y] - b[x][v-1] + b[u-1][v-1];
		}
		cout << ret << "\n";
	}
	
	return 0;
} 

问题

  • m.count()只返回0/1;即元素是否存在

代码:

  • map写法
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 2e5 + 10;

int n, k, q;
int l[N], r[N];
int a, b;
int i;
map<int,int> m;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	cin >> n >> k >> q;
	
	while(n--)
	{
		i++; 
		cin >> l[i] >> r[i];
		for(int j = l[i]; j <= r[i]; j++)
		{
			m[j]++;
		}
	}
	
	while(q--)
	{
		cin >> a >> b;
		int ret = 0;
		for(int j = a; j <= b; j++)
		{
			int n 	um = m[j]; 
			if(num >= k)
			{
				ret++;
			}
		}
		cout << ret << "\n";
	}
	
	return 0; 
 } 
  • 差分/前缀和写法
cpp 复制代码
#include<stdio.h>
using namespace std;
int f[200005];
int main(){
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	int i;
	int max=0;
	for(i=1;i<=n;i++)
	{//差分代码
		int a,b;
		scanf("%d%d",&a,&b);// 读取推荐温度区间 [a, b]
		f[a]+=1;// 【差分标记】在起点 a 处 +1
		f[b+1]-=1;// 【差分标记】在终点后一位 b+1 处 -1
		if(b>max)max=b; // 记录最大的右边界,优化后续循环
	}
	for(i=1;i<=max;i++)
	{ //用求前缀和的方法还原差分数组 
		f[i]=f[i-1]+f[i];
	}
	for(i=1;i<=200000;i++)
	{//预处理(前缀和)  如果当前温度 i 的推荐数 >= m (即题目中的k),则标记为1,否则为0
		if(f[i]>=m)f[i]=1+f[i-1];// 是有效温度:在前一个前缀和的基础上 +1
		else f[i]=f[i-1];// 是无效温度:继承前一个前缀和的值
	}
	for(i=1;i<=k;i++)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%d\n",f[r]-f[l-1]);//前缀和计算
	}
	return 0;
} 

4.8 k 倍区间

!洛谷

P8649 [蓝桥杯 2017 省 B] k 倍区间

P8649 [蓝桥杯 2017 省 B] k 倍区间 - 洛谷

题目描述

给定一个长度为 N N N 的数列, A 1 , A 2 , ⋯ A N A_1,A_2, \cdots A_N A1,A2,⋯AN,如果其中一段连续的子序列 A i , A i + 1 , ⋯ A j ( i ≤ j ) A_i,A_{i+1}, \cdots A_j(i \le j) Ai,Ai+1,⋯Aj(i≤j) 之和是 K K K 的倍数,我们就称这个区间 [ i , j ] [i,j] [i,j] 是 K K K 倍区间。

你能求出数列中总共有多少个 K K K 倍区间吗?

输入格式

第一行包含两个整数 N N N 和 K K K ( 1 ≤ N , K ≤ 10 5 ) (1 \le N,K \le 10^5) (1≤N,K≤105)。

以下 N N N 行每行包含一个整数 A i A_i Ai ( 1 ≤ A i ≤ 10 5 ) (1 \le A_i \le 10^5) (1≤Ai≤105)。

输出格式

输出一个整数,代表 K K K 倍区间的数目。

输入输出样例 #1

输入 #1

复制代码
5 2
1  
2  
3  
4  
5  

输出 #1

复制代码
6

说明/提示

时限 2 秒, 256M。蓝桥杯 2017 年第八届

思路:

同余定理:

假设我们有一个数组的前缀和数组 b b b。

如果两个前缀和 b [ i ] b[i] b[i] 和 b [ j ] b[j] b[j] 对 k k k 取模的结果相同(即 b [ i ] ≡ b [ j ] ( m o d k ) b[i] \equiv b[j] \pmod k b[i]≡b[j](modk)),那么它们之间的差值一定是 k k k 的倍数。

代码:

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e5 + 10;

ll n, k;
ll a[N];
ll b[N];
ll c[N];
ll ret; 
ll num; 

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	cin >> n >> k;
	for(int i= 1; i<= n; i++)
	{
		cin >> a[i];//读入数组
		b[i] = b[i-1] + a[i];//构造前缀和数组 
	
	}
	
	for(int i = 0; i<= n; i++)
	{
		ret += c[b[i]%k]++;//核心
	}
	
	
	cout << ret;
	
	
	return 0;
 } 

5. 蓝桥杯真题

5.1 蓝桥杯 2025 省赛 C++ B组(第二场)

5.1.1 密密摆放

!洛谷

P12337 [蓝桥杯 2025 省 AB/Python B 第二场] 密密摆放

P12337 [蓝桥杯 2025 省 AB/Python B 第二场] 密密摆放 - 洛谷

题目描述

小蓝有一个大箱子,内部的长宽高分别是 200 200 200、 250 250 250、 240 240 240(单位:毫米),他要用这个大箱子来放一些同样大小的小盒子,小盒子的外部长宽高分别是 30 30 30、 40 40 40、 50 50 50(单位:毫米)。小盒子允许从各个方向旋转(包括可以平放和倒放)。

请问小蓝最多可以在一个大箱子里面放多少个小盒子。

输入格式

输出格式

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只需要编写一个程序输出这个整数,输出多余的内容将无法得分。

代码:
cpp 复制代码
#include<iostream>

using namespace std;

int main()
{
    cout << 8*5*5 ;
    return 0;
}

5.1.2 脉冲强度之和

!洛谷

P12338 [蓝桥杯 2025 省 B/Python B 第二场] 脉冲强度之和

P12338 [蓝桥杯 2025 省 B/Python B 第二场] 脉冲强度之和 - 洛谷

题目描述

在蓝桥电子工坊,工程师小蓝正在设计一款智能脉冲生成器,用于驱动一种新型设备。该设备的运行依赖于特定的脉冲强度,用正整数 p p p 表示,其必须满足以下三个条件:

  1. 可由连续 10 10 10 个正整数之和组成:即存在一个正整数 k k k,使得脉冲强度 p = k + ( k + 1 ) + ( k + 2 ) + ⋯ + ( k + 9 ) p = k + (k + 1) + (k + 2) + \cdots + (k + 9) p=k+(k+1)+(k+2)+⋯+(k+9)。
  2. 各个数位上的数字都相同:例如 1111 1111 1111、 22222 22222 22222、 333333 333333 333333 等。
  3. 数值不超过 20255202 20255202 20255202:即 1 ≤ p ≤ 20255202 1 \leq p \leq 20255202 1≤p≤20255202。

通过计算所有符合条件的脉冲强度之和,小蓝能够优化设备运行模式。对此,请帮助他计算这一总和。

输入格式

输出格式

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只需要编写一个程序输出这个整数,输出多余的内容将无法得分。

思路:
  • 暴力枚举
代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

// typedef unsigned long long ll;

// ll p, k;
// ll ret;

// int isright(ll x)
// {
// 	if(x-10 < 0)return 1;
	
// 	string s = to_string(x);
	
	
// 	for(int i = 1; i< s.size(); i++)
// 	{
// 		if(s[i] != s[0])return 0;
// 	}
	
// 	cout << "p = " << x << endl;
	
// 	return x;
// }

int main()
{
	// for(int i = 1; p < 20255202; i++)
	// {
	
	// 		p = 0;
	// 		for(int k = i; k <= i+9; k++)
	// 		{
	// 			p += k;
	// 		}
	// 		ret += isright(p);
	// 		if(isright(p))cout << "i=" << i << "\n";
	
		
	// }
	
	// cout << "符合条件的脉冲强度之和=" <<  ret;

    cout << "6172830";
	
	return 0;
 } 

5.1.3 25 之和

!洛谷

P12339 [蓝桥杯 2025 省 B/Python B 第二场] 25 之和

P12339 [蓝桥杯 2025 省 B/Python B 第二场] 25 之和 - 洛谷

题目描述

小蓝最近对求和很着迷,给定一个正整数 n n n,他想求从 n n n 开始的连续 25 25 25 个整数的和,即 n + ( n + 1 ) + ( n + 2 ) + ⋯ + ( n + 24 ) n + (n + 1) + (n + 2) + \cdots + (n + 24) n+(n+1)+(n+2)+⋯+(n+24),请帮帮他吧。

输入格式

输入一行包含一个正整数 n n n。

输出格式

输出一行包含一个整数表示答案。

输入输出样例 #1

输入 #1

复制代码
1

输出 #1

复制代码
325

输入输出样例 #2

输入 #2

复制代码
100

输出 #2

复制代码
2800

说明/提示

评测用例规模与约定

  • 对于 40 % 40\% 40% 的评测用例, 1 ≤ n ≤ 100 1 \leq n \leq 100 1≤n≤100;
  • 对于所有评测用例, 1 ≤ n ≤ 10000 1 \leq n \leq 10000 1≤n≤10000。
代码:
cpp 复制代码
#include<iostream>

using namespace std;

typedef unsigned long long ll;

ll n;
ll sum;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n;
    cout << 25*n+(1+24)*24/2;

    return 0;
}

5.1.4 旗帜

!洛谷

P12340 [蓝桥杯 2025 省 AB/Python B 第二场] 旗帜

P12340 [蓝桥杯 2025 省 AB/Python B 第二场] 旗帜 - 洛谷

题目描述

小蓝要画一个 LANQIAO 图形,并把这个图形做成一个旗帜。图形的形状为一个 h × w h \times w h×w 的矩形,其中 h h h 表示图形的高, w w w 表示图形的宽。当 h = 5 , w = 10 h = 5, w = 10 h=5,w=10 时,图形如下所示:

复制代码
LANQIAOLAN
ANQIAOLANQ
NQIAOLANQI
QIAOLANQIA
IAOLANQIAO

图形的规律是:第一行用 LANQIAO 重复填入,第二行开始,每行向左移动一个字符,用 LANQIAO 重复填入。

小蓝需要把图形中的每个字母都剪出来,以粘贴到旗帜上,他想知道,给定图形的高和宽,图形中有多少个 A

输入格式

输入的第一行包含两个正整数 h , w h, w h,w,用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

输入输出样例 #1

输入 #1

复制代码
5 10

输出 #1

复制代码
14

说明/提示

评测用例规模与约定

  • 对于 30 % 30\% 30% 的评测用例, h = 1 h = 1 h=1, 1 ≤ w ≤ 20 1 \leq w \leq 20 1≤w≤20;
  • 对于 60 % 60\% 60% 的评测用例, 1 ≤ h , w ≤ 20 1 \leq h, w \leq 20 1≤h,w≤20;
  • 对于所有评测用例, 1 ≤ h , w ≤ 100 1 \leq h, w \leq 100 1≤h,w≤100。
思路:

模拟

代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

int a[8][8] ={{6, 7, 1, 2, 3, 4, 5, 0},
			  {7, 1, 2, 3, 4, 5, 6, 0},
			  {1, 2, 3, 4, 5, 6, 7, 0},
			  {2, 3, 4, 5, 6, 7, 1, 0},
			  {3, 4, 5, 6, 7, 1, 2, 0},
			  {4, 5, 6, 7, 1, 2, 3, 0},
			  {5, 6, 7, 1, 2, 3, 4, 0},
			  {0, 0, 0, 0, 0, 0, 0, 0}};
ll h, w;
ll ret;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
    
	cin >> h >> w;
	
	for(int i= 1; i <= h; i++)
	{
//		cout << "i=" << i << " ";
		for(int j = 1; j <= w; j++)
		{
//			cout << "j=" << j << endl;
			if(a[i%7][j%7] == 2||a[i%7][j%7] == 6)
			{
//				cout << "a[i%7][j%7]=" << a[i%7][j%7] << endl;
				ret++;
			}
		}
	}
	
	cout << ret;
	
	return 0;
}

5.1.5 数列差分

!洛谷

P12342 [蓝桥杯 2025 省 B/Python B 第二场] 数列差分

P12342 [蓝桥杯 2025 省 B/Python B 第二场] 数列差分 - 洛谷

题目描述

小蓝有两个长度均为 n n n 的数列 A = { a 1 , a 2 , ⋯   , a n } A=\{a_1, a_2, \cdots, a_n\} A={a1,a2,⋯,an} 和 B = { b 1 , b 2 , ⋯   , b n } B=\{b_1, b_2, \cdots, b_n\} B={b1,b2,⋯,bn},将两个数列作差定义为 C = A − B = { c 1 = a 1 − b 1 , c 2 = a 2 − b 2 , ⋯   , c n = a n − b n } C=A-B=\{c_1=a_1-b_1, c_2=a_2-b_2, \cdots, c_n=a_n-b_n\} C=A−B={c1=a1−b1,c2=a2−b2,⋯,cn=an−bn}。小蓝将对数列 B B B 进行若干次操作,每次操作可以将数列 B B B 中的任意一个数更改为任意一个整数。在进行完所有操作后,小蓝可以按任意顺序将数列 B B B 重排,之后再计算数列 C C C。小蓝想知道,最少操作多少次可以使得数列 C C C 中的所有数都为正整数。

输入格式

输入的第一行包含一个正整数 n n n;

第二行包含 n n n 个整数 a 1 , a 2 , ⋯   , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an,相邻整数之间使用一个空格分隔。

第三行包含 n n n 个整数 b 1 , b 2 , ⋯   , b n b_1, b_2, \cdots, b_n b1,b2,⋯,bn,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

输入输出样例 #1

输入 #1

复制代码
4
22 31 12 14
3 19 27 44

输出 #1

复制代码
1

说明/提示

样例说明

其中一种方案:将 44 44 44 改为 0 0 0,重新排列 B B B 为 { 19 , 27 , 3 , 0 } \{19, 27, 3, 0\} {19,27,3,0},使得数列 C = { 3 , 4 , 9 , 14 } C=\{3, 4, 9, 14\} C={3,4,9,14} 均为正整数。

评测用例规模与约定

  • 对于 30 % 30\% 30% 的评测用例, n ≤ 10 n \leq 10 n≤10;
  • 对于所有评测用例, 1 ≤ n ≤ 10 5 1 \leq n \leq 10^5 1≤n≤105, − 10 9 ≤ a i ≤ 10 9 -10^9 \leq a_i \leq 10^9 −109≤ai≤109, − 10 9 ≤ b i ≤ 10 9 -10^9 \leq b_i \leq 10^9 −109≤bi≤109。
思路

贪心

感觉思路其实有问题,但是样例全过了

代码:
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e5 +10; 

ll a[N];
ll b[N];
ll n;
ll ret;
ll k;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	
	cin >> n;
	
	
	for(int i = 1; i<= n; i++) cin >> a[i];
	for(int i = 1; i<= n; i++) cin >> b[i];
	
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	
	for(int i = 1; i<= n; i++)
	{
		if(b[i-k] >= a[i])
		{
			ret++;
			k++;
		}
	}
	
	cout << ret;
	
	return 0; 
}
  • 正常 双指针+贪心做法
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 +10; 

ll a[N], b[N];
int n;

int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) cin >> b[i];
    
    sort(a+1, a+n+1);
    sort(b+1, b+n+1);
    
    int j = 1; // b 的指针
    int success = 0; // 成功匹配的对数
    
    // 贪心:尝试为每一个 a[i] 找一个最小的、且小于它的 b[j]
    for(int i = 1; i <= n; i++) 
    {
        // 如果当前的 b 比 a 小,说明匹配成功
        if(j <= n && b[j] < a[i]) 
        {
            success++;
            j++; // 这个 b 用过了,看下一个 b
        }
        // 如果 b[j] >= a[i],说明 b 太大了,这个 a[i] 没法匹配当前的 b
        // 但 a[i] 也没法匹配后面更大的 b,所以这个 a[i] 只能放弃(或者说对应的 b 需要被修改)
        // 实际上,我们是在统计有多少个 b 能留下来。
    }
    
    // 答案 = 总数 - 能留下的 b 的数量
    cout << n - success << endl;
    
    return 0;
}

相关推荐
小贾要学习2 小时前
【Linux】应用层自定义协议与序列化
linux·服务器·c++·json
CoderCodingNo2 小时前
【GESP】C++二级真题 luogu-B4497, [GESP202603 二级] 数数
开发语言·c++·算法
磊 子2 小时前
八大排序之冒泡排序+选择排序
数据结构·算法·排序算法
We་ct2 小时前
LeetCode 50. Pow(x, n):从暴力法到快速幂的优化之路
开发语言·前端·javascript·算法·leetcode·typescript·
潇洒畅想2 小时前
1.1 从∑到∫:用循环理解求和与累积
java·数据结构·python·算法
郝学胜-神的一滴3 小时前
[简化版 GAMES 101] 计算机图形学 04:二维变换上
c++·算法·unity·godot·图形渲染·unreal engine·cesium
ZC跨境爬虫3 小时前
海南大学交友平台开发实战day7(实现核心匹配算法+解决JSON请求报错问题)
前端·python·算法·html·json
来日可期13143 小时前
C/C++ 反常识记录(1)—— 那些容易踩坑的语法细节
c语言·开发语言·c++
计算机安禾3 小时前
【数据结构与算法】第41篇:图论(五):拓扑排序与关键路径
c语言·数据结构·c++·算法·图论·visual studio