梦熊 NOIP第一场题解

P11267 【MX-S5-T1】王国边缘

原题链接

这道题做的时候看出来了是基环树,但没想到倍增,用特殊性质过了 20 p t s 20pts 20pts,该说不说,梦熊的题确实很难。

老样子,简化题意:

给定一个长度为 n 的 01 01 01字符串 T = S ∞ 。 T = S∞。 T=S∞。

一个人在 T T T 上移动。他的一次移动为:设当前下标为 x x x,则跳

到 [ x + 1 , x + m ] [x + 1, x + m] [x+1,x+m] 中最后一个为 1 1 1 的位置,如果区间中不存在 1 1 1则移动至 x + 1 x + 1 x+1。有 q 次询问,每次询问给定 x , y x, y x,y,求从 x x x 开始移动 y y y 次后的下标对 1 0 9 + 7 10^9 + 7 109+7 取模的值。

分析思路

先考虑对于
1 ∼ n 1\sim n 1∼n中的每个点往后跳一次会跳多少距离。

那么我们来想一下,为什么我们只需要考虑 1 ∼ n 1\sim n 1∼n的点,而不需要找别的距离。

我们能发现,由于字符串是无限循环的,所以1对于位置模上 n n n的结果相同时,那么往后跳的距离也是相同的。

我们可以先将字符串断成环成链倍长后做前缀和来处理 l ∼ r l\sim r l∼r中的 1 1 1的数量。

然后很容易想出二分得出往后跳的距离。

然后我们就可以求出对于每个点 i i i往后可以跳跃的距离。

然后问题询问的是往后跳 k k k次的最终位置。

经典的倍增,但我就是没看出来,寄了。

c o d e code code

T2 P11268 【MX-S5-T2】买东西题

原题链接

这道题本来想打特殊性质的,感觉生活应用题都还好想一点,但还是打寄了,哎。(っ °Д °;)っ

简化题意:

你要买 n n n个物品,第 i i i个物品原价 a i a_i ai,折扣价 b i b_i bi。

你还有 m m m 个优惠券,第 i i i 个优惠券形如原原原价价价满 w i w_i wi 减 v i v_i vi。

对于第 i i i 个物品,你可以选择以下三种购买方式之一:

  1. 使用原价 a i a_i ai 购买。
  2. 使用折扣价 b i b_i bi 购买。
  3. 选择一个优惠券 j j j,要求满足 a i ≥ w i a_i\ge w_i ai≥wi,使用优惠券 j j j,以 a i − v j a_i-v_j ai−vj 的价格购买。

注意每个优惠券 j j j只能被最多一个 i i i使用。

求购买所有物品最少用钱。

解题思路:

可以这样理解: a a a元的物品有 b b b元的折扣,就相当于 a a a元的物品有一张 a − b a-b a−b的优惠券。

因为一张优惠券是满 w w w元才可以用,所以可以用的物品在价格 a a a上是一段区间 [ a , inf ⁡ ] [a,\inf] [a,inf]。

有一个很朴素的想法是,将每一个物品最多能省多少钱先弄出来,然后用优惠券想办法把省的最小的钱换成优惠券。

先将物品和优惠券按满多少可以有优惠排序,再枚举优惠券,最后就是按照上面说的逐步加进去就好了。

想要快速求出最小值可以用优先队列,如果到最后还用不到优惠券的记得把打得折加进去。

时间复杂度还是很优的,仅要 O ( n l o g n ) O(n log n) O(nlogn)

c o d e code code

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define maxn 1000050
#define gll greater<int>
#define vll vector<int>
using namespace std;
inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
		x = x * 10 + ch - '0', ch = getchar();
	return x * f;
}
int n, m;
struct node {
	int x, y;
} a[maxn], b[maxn];
bool cmp(node a, node b) {
	//不能写成下面的形式,会爆范围
//	if(a.x==a.y) return a.y>b.y;
//	else return a.x>b.x;
	return a.x == b.x ? a.y > b.y : a.x > b.x;
}
int res = 0;
priority_queue<int, vll, gll > q;
signed main() {
	n = read(), m = read();
	for (int i = 1; i <= n; i++) {
		int x, y;
		x = read();
		y = read();
		a[i].x = x, a[i].y = x - y;
		res += a[i].x;
	}
	for (int i = 1; i <= m; i++) {
		b[i].x = read(), b[i].y = read();
	}
	int i = 1;
	sort(a + 1, a + n + 1, cmp);
	sort(b + 1, b + m + 1, cmp);
	for (int j = 1; j <= m; j++) {
		while (i <= n && a[i].x >= b[j].x) {
			q.push(a[i].y);
			i++;
		}
		if (q.size() && q.top() < b[j].y) {
			q.pop();
			q.push(b[j].y);
		}
	}
	while (i <= n) {
		q.push(a[i].y);
		i++;
	}
	while (q.size()){
		res -= q.top();
		q.pop();
	}
	cout << res;
	return 0;
}

T3 P11269 【MX-S5-T3】IMAWANOKIWA (Construction ver.)

原题链接

题目太复杂,表示读懂稍许困难。

简化题意:

给你一个初始长度为 n n n,只包含 0 , 1 , 2 0, 1, 2 0,1,2 的序列 a 1 ∼ n a_1∼n a1∼n,你每次可以选择两个相邻的数 p , q p, q p,q,删去它们,并在原位置插入
p o p c ( p + q ) 。 popc(p + q)。 popc(p+q)。其中, p o p c ( x ) popc(x) popc(x) 表示 x x x在二进制表示下 1 1 1 的个数。

显然每次操作后序列长度都会减少 1 1 1,所以执行 n − 1 n − 1 n−1 次操作

后,这个序列会恰好剩下一个数。请你最小化剩下的这个数,并

给出字典序最小的操作位置序列。

题目思路:

T4

简化题意:

有 n + m n + m n+m 个括号序列,分别是 S 1 , S 2 , S 3 , . . . , S n S1, S2, S3, . . . , Sn S1,S2,S3,...,Sn 和
T 1 , T 2 , T 3 , . . . , T m 。 T1, T2, T3, . . . , Tm。 T1,T2,T3,...,Tm。

对一个括号序列 A , f ( A ) A,f(A) A,f(A)为满足以下条件的 ( i , j ) (i, j) (i,j) 对数:

  1. i ∈ [ 1 , n ] , j ∈ [ 1 , m ] ; 1.i ∈ [1, n],j ∈ [1, m]; 1.i∈[1,n],j∈[1,m];
  2. S i 2.Si 2.Si 是 A A A 的前缀且 T j Tj Tj 是 A A A 的后缀。

求所有长度为 k k k 的合法括号序列 S , f ( S ) S,f(S) S,f(S) 的和。答案对
1 0 9 + 7 10^9 + 7 109+7 取模。

保证 k 为偶数。

$$$$$$$$$$$$$$$$$$$$$$$$

相关推荐
机器视觉知识推荐、就业指导16 分钟前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
Yang.992 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
熬夜学编程的小王2 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
zz40_2 小时前
C++自己写类 和 运算符重载函数
c++
六月的翅膀2 小时前
C++:实例访问静态成员函数和类访问静态成员函数有什么区别
开发语言·c++
liujjjiyun3 小时前
小R的随机播放顺序
数据结构·c++·算法
¥ 多多¥3 小时前
c++中mystring运算符重载
开发语言·c++·算法
天若有情6734 小时前
c++框架设计展示---提高开发效率!
java·c++·算法
Root_Smile4 小时前
【C++】类和对象
开发语言·c++