暑假集训 2

文章目录

  • T1
  • T2
  • T3
  • T4
  • T5


T1

题目描述

Mirko很快厌倦了Jetpack Joyride并开始在他的手机上玩神奇宝贝GO。这个游戏的玩点之一就是神奇宝贝的进化。 为了进化物种为Pi的神奇宝贝,Mirko必须提供Ki个用于该物种神奇宝贝的糖果。在神奇宝贝进化后,他能拿回2个糖果。神奇宝贝只能在为他们的物种准备的糖果的帮助下进化。 Mirko有N种神奇宝贝,并且为物种Pi的神奇宝贝提供Mi个糖果,他想知道他可以进化多少次神奇宝贝。 他还想知道哪个神奇宝贝可以进化最多次。如果有多个这样的神奇宝贝,输出一个编号最小的神奇宝贝。换句话说,在输入数据中最早出现的那个。

输入

第一行输入包含整数N(1≤N≤70)。表示神奇宝贝种类的数量。接下来2N行包含N组数据,其中包含: ●第2i行包含字符串Pi,由最多20个字组成。表示第i种神奇宝贝的名称; ●第2i+1行包含整数Ki(12≤Ki≤400)和Mi(1≤Mi≤104),分别第i种神奇宝贝的进化所需的糖果数量和Mirko为这种神奇宝贝准备的糖果总数。

输出

第一行输出一个整数。表示Mirko可以进化的神奇宝贝的总次数。 第二行输出一个字符串。表示可以进化最多次的神奇宝贝的名称。

样例输入

4
Caterpie
12 33
Weedle
12 42
Pidgey
12 47
Rattata
25 71

样例输出

14
Weedle

题解

水题,按照题目模拟就能过

代码

#include 
#include 
#include 
#include 
#include 

using namespace std;

const int N = 75;

string name, p;

int n, ans, maxn;
int k[N], m[N];

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) {
        int cnt = 0;
        cin >> name;
        scanf("%d%d", &k[i], &m[i]);
        while(m[i] >= k[i]) {
            cnt ++;
            m[i] -= k[i];
            m[i] += 2;
        }
        ans += cnt;
        if(cnt > maxn)
            p = name, maxn = cnt;
    }
    cout << ans << endl << p << endl;
}

T2

题目描述

小 Zeljko 一直在阁楼里读他奶奶的旧信,并且发现了一个长度为 N 的单词。 不幸的是,由于溢出的墨水,他不知道单词的内容。他把看不清的 M 个字母每 个字母都用一个字符’#‘替换后,在一张纸上重写了这个词。他把那张纸递给 了他的奶奶,对于每个看不清的字母,奶奶给了他 K 个不同的可能。在那之后, Zeljko 在笔记本中写下了所有可能的单词,并决定仔细查看他们的属性,以确 定原始单词是什么。在看到笔记本上写下的单词后,他的奶奶意识到他们正在 寻找的是按字典序排列的第 X 个单词。Zeljko 在他们学校学习字母表的那天生 病了,所以他要求你帮助他确定原来的单词。 输入 第一行输入包含整数 N,M,K 和 X(1≤N≤500,1≤M≤N,1≤K≤26,1≤X≤ 1e9)。分别表示单词的长度,看不清的字母的数量,奶奶给出的字母的数量和 原单词是字典序的第几个。 第二行输入包含一个长度为 N 的字符串,由小写英文字母和字符’#‘组成。 表示 Zeljko 找到的单词,其中字符’#'表示看不清的字母。 接下来 M 行中的每一行包含一个长度为 K 的字符串,由 K 个不同的小写英文 字母组成。第 2+i 行的 K 个字母表示第 i 个看不清的 保证 X 总是小于等于能构造出的单词的总数。

输入

第一行输入包含整数 N,M,K 和 X(1≤N≤500,1≤M≤N,1≤K≤26,1≤X≤ 1e9)。分别表示单词的长度,看不清的字母的数量,奶奶给出的字母的数量和 原单词是字典序的第几个。 第二行输入包含一个长度为 N 的字符串,由小写英文字母和字符’#‘组成。 表示 Zeljko 找到的单词,其中字符’#'表示看不清的字母。 接下来 M 行中的每一行包含一个长度为 K 的字符串,由 K 个不同的小写英文 字母组成。第 2+i 行的 K 个字母表示第 i 个看不清的字母的 K 种可能。 保证 X 总是小于等于能构造出的单词的总数。

输出

输出一个字符串。表示原本的单词。

样例输入

9 2 3 7
po#olje#i
sol
znu

样例输出

posoljeni

题解

比上一题难一点,但也不难想到正解
很显然一共有 k m k^m km种可能,所以对于按字典序排的第 x x x种可能的每一位我们只需要不断地向 k k k取模
假设我们需要确定第 i i i位,令 y = x % k y=x\%k y=x%k,那么第 i i i位的字母就是这个字母的所有可能中按字典序排第 y y y位的字母

代码

#include 
#include 
#include 
#include 

using namespace std;

const int N = 505;
const int K = 30;

int n, m, k, x, cnt, p, q;
char s[N], a[N][K], ans[N];

int main() {
	scanf("%d%d%d%d\n", &n, &m, &k, &x);
	gets(s + 1);
	for(int i = 1; i <= m; i ++) {
		scanf("\n");
		for(int j = 1; j <= k; j ++) {
			a[i][j] = getchar();
		}
	}
	for(int i = 1; i <= m; i ++)
		sort(a[i] + 1, a[i] + 1 + k);
	for(int i = m;i >= 1; i --) {
		q = p = x % k;
		if(p == 0) p = k;
		ans[i] = a[i][p];                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
		x /= k;
		if(q != 0) x ++;
	}
	for(int i = 1; i <= n; i ++) {
		if(s[i] == '#') {
			cnt ++;
			s[i] = ans[cnt];
		}
		putchar(s[i]);
	}
	putchar('\n');
	return 0;
}

T3

题目描述

Do Geese See God?或者,Was It A Rat I Saw?没关系,这只是展示 Mislav 对回文的热爱的不必要的介绍。帮他解决以下任务! 设 A 是 N 个整数构成的数组。我们说 A 是回文,如果 A[i]=A[N-i+1]对于每 个 i 都成立,其中 A[i]表示数组 A 的第 i 个元素,并且数组中的第一个元素编 号是 1。 Mislav 可以通过以下方式修改数组:在一次操作中,他选择该数组的两个 相邻元素并用它们的和替换它们。注意,每次操作后数组中元素的数量将减少 1。 Mislav 想知道为了让数组变为回文的,他必须做出最少多少次操作。

输入

第一行输入包含整数 N(1≤N≤1e6),表示数组中的元素个数。 第二行输入包含 N 个用空格分隔的正整数,表示 Mislav 数组中的元素。数组中的数字最多为 1e9。

输出

输出一个整数。表示 Mislav 要把数组变为回文所需的最少操作次数。

样例输入

3
1 2 3

样例输出

1

题解

这道题用 O ( n ) O(n) O(n)的复杂度就可以过
我们用两个指针 l l l r r r,先分别指向数列的最左断和最右端,假设数列为 a a a
如果 a [ l ] < a [ r ] a[l]<a[r] a[l]<a[r],那么 l + + , a [ l ] + = a [ l − 1 ] l++,a[l]+=a[l-1] l++,a[l]+=a[l1]
如果 a [ l ] > a [ r ] a[l]>a[r] a[l]>a[r],那么 r − − , a [ r ] + = a [ r + 1 ] r--,a[r]+=a[r+1] r,a[r]+=a[r+1]
如果 a [ l ] = = a [ r ] a[l]==a[r] a[l]==a[r],那么 l + + , r − − l++,r-- l++,r

代码

#include 
#include 
#include 
#include 
#include 

using namespace std;

#define LL long long

const int N = 1000005;

LL ans;
LL a[N];
int n, l, r;

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++)
		scanf("%lld", &a[i]);
	l = 1, r = n;
	while(l <= r) {
		if(a[l] < a[r]) {
			ans ++, l ++;
			a[l] += a[l - 1];
		}
		else {
			if(a[l] > a[r]) {
				ans ++, r --;
				a[r] += a[r + 1];
			}
			else
				l ++, r --;
		}
	}
	printf("%lld\n", ans);
}

T4

题目描述

Slavko 很无聊,所以他把正整数填到 N*N 的方阵中。
如果他填出来的方阵满足以下条件,他会特别高兴:
●每行中的数字的平均值是一个位于同一行的整数。
●每列中的数字的平均值是一个位于同一列的整数。
●表中的所有数字都不同。
帮助 Slavko 找到一种会让他开心的填法。

输入

第一行输入包含整数 N(1≤N≤100)。表示方阵的行数和列数。

输出

输出 N 行,每行输出 N 个由空格分隔的整数。令第 i 行中的第 j 个数字对应于 Slavk将在方阵的第 i 行第 j 列写下的值。
所有数字必须大于 0 且小于 1e9。
如果有多个解决方案,则输出任意一个。
如果没有任何解决方案,则输出-1。

样例输入

3

样例输出

1 2 3
4 5 6
7 8 9

题解

我们分别考虑当 n n n为奇数和偶数的情况
1、 n n n为奇数
直接按顺序输出即可
2、 n n n为偶数
这道题的难点就在此了,对于一个 n ∗ n n*n nn的矩阵的填充,我们先从第一行填起
不妨设第一行的前 n − 1 n-1 n1个数为 [ 1 , 2 … … n − 1 ] \begin{bmatrix}1,2……n-1\end{bmatrix} [1,2n1],通过计算可得第 n n n个数为 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n1)
为了避免重复,我们将第二行置为 [ 1 + n ( n − 1 ) 2 , 2 + n ( n − 1 ) 2 … … n − 1 + n ( n − 1 ) 2 ] \begin{bmatrix}1+\frac{n(n-1)}{2}, 2+\frac{n(n-1)}{2}……n-1+\frac{n(n-1)}{2}\end{bmatrix} [1+2n(n1),2+2n(n1)n1+2n(n1)]
最后一行需要单独处理,假设矩阵的最后一行有一元素 a [ n ] [ i ] a[n][i] a[n][i],那么如何计算 a [ n ] [ i ] a[n][i] a[n][i]
根据平均数的计算方法,我们可以倒推 a [ n ] [ i ] a[n][i] a[n][i]
a [ n ] [ i ] = n ∗ a [ n − 1 ] [ i ] − ∑ j = 1 n − 1 a [ j ] [ i ] a[n][i] = n*a[n-1][i]-\sum_{j=1}^{n-1}a[j][i] a[n][i]=na[n1][i]j=1n1a[j][i]

最后我们可以发现,偶数情况的处理方法对奇数同样适用

代码

#include 
#include 
#include 
#include 

using namespace std;

const int N = 105;

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

int main() {
	scanf("%d", &n);
	if(n == 1) {
		printf("1\n");
		return 0;
	}
	if(n == 2) {
		printf("-1\n");
		return 0;
	}
	for(int i = 1; i <= n - 1; i ++)
		a[1][i] = i;
	a[1][n] = n * (n - 1) / 2;
	for(int i = 2; i <= n - 1; i ++) 
		for(int j = 1; j <= n; j ++)
			a[i][j] = a[i - 1][j] + a[1][n];
	for(int i = 1; i <= n; i ++) {
		int sum = 0;
		for(int j = 1; j <= n - 1; j ++)
			sum += a[j][i];
		a[n][i] = n * a[n - 1][i] - sum;
	}
	for(int i = 1; i <= n; i ++) {
		for(int j = 1; j <= n - 1; j ++)
			printf("%d ", a[i][j]);
		printf("%d\n", a[i][n]);
	}
	return 0;
}

T5

题目描述

Dominik 想象出了一系列正整数 P1,P2,…,PN。让我们将他们排序之后的版 本称为 Q1,Q2,…,QN。 此外,他想象出了一个允许替换集合。如果一对(X,Y)是允许替换集合的 成员,Dominik 可以交换数组 P 中位于 X 和 Y 处的数字。 Marin 向 Dominik 进行了 T 次查询,每个查询都属于以下类型之一: 1.把数组 P 中位于 A 和 B 位置的两个数字交换。 2.将(A,B)添加到允许替换集合中。Marin 可能给出已经在允许替换集合 中的数对(A,B)。 3.看看是否可以仅使用允许替换集合中的替换进行排序?可以以任意顺序 使用替换,并且可以使每个替换任意次数。 4.如果位于 A 位置的数字可以仅使用允许的替换转移到位置 B,那么我们称 A 和 B 是链接的。我们把所有和 A 链接的位置构成的集合称为 A 的云。如果对于 一个云中的每个元素 j,都能在仅使用允许替换集合中的替换使得 Pj=Qj,那么 我们称这个云是好的。你必须回答有多少对不同的满足以下条件的位置(A,B): ①位置 A 和 B 不是链接的②A 和 B 的云都不是好的③如果我们将对(A,B)添加 到允许的替换集合中,A 的云(通过使 A 和 B 成为链接的来得到)变为好的。 请注意:对(A,B)和(B,A)被认为是完全相同的一对位置。

输入

第一行输入包含整数 N 和 M(1≤N,M≤1e6)。分别表示数组 P 的大小和查 询的次数。 第二行输入包含 N 个整数 P1,P2,…,PN(1≤Pi≤1e6)。表示数组 P。 接下来 M 行中的每一行都包含以下格式的查询: ●行中的第一个数字是查询的类型 T。类型有 1,2,3,4 四种,对应题目中说 的四种查询。 ●如果是查询类型 T 是 1 或 2,会跟着两个不同的整数 A 和 B(1≤A,B≤N)。 表示前两种询问中的(A,B)。

输出

对于每个类型 T 为 3 或 4 的查询,在单独的一行中输出答案。 查询类型 3 的答案是“DA”(表示可以只通过替换排序)或“NE”(表示不 可以只通过替换排序),没有引号。 查询类型 4 的查询答案是一个非负整数。表示满足条件的位置对的数量。

样例输入

4 10
2 1 4 3
3
4
1 1 2
3
4
2 2 3
2 1 2
4
2 3 4
3

样例输出

NE
2
NE
1
3
DA

题解

这题还没码出来,好像要用什么玄学的字符串哈希来做

你可能感兴趣的:(总结)