UVa - 1618 - Weak Key

Cheolsoo is a cryptographer in ICPC(International Cryptographic Program Company). Recently, Cheolsoo developed a cryptographic algorithm called ACM(Advanced Cryptographic Method). ACM uses a key to encrypt
a message. The encrypted message is called a cipher text. In ACM, to decrypt a cipher text, the same key used in the encryption should be applied. That is, the encryption key and the decryption key are the same. So, the sender and receiver should
agree on a key before they communicate securely using ACM. Soon after Cheolsoo finished the design of ACM, he asked its analysis on security to Younghee who is a cryptanalyst in ICPC.

Younghee has an interest in breaking cryptosystems. Actually, she developed many attacking methods for well-known cryptographic algorithms. Some cryptographic algorithms have weak keys. When a message is encrypted with a weak key, the message can be
recovered easily without the key from the cipher text. So, weak key should not be used when encrypting a message. After many trials, she found the characteristic of weak keys in ACM. ACM uses a sequence of mutually distinct positive integers (N1N2,..., Nk) as
a key. Younghee found that weak keys in ACM have the following two special patterns:

There are four integers NpNqNrNs(1p < q < r < sk) in
the key such that

(1) Nq > Ns > Np > Nr or Nq < Ns < Np < Nr

For example, the key (10, 30, 60, 40, 20, 50) has the pattern in (1); (_, 30, 60, _, 20, 50). So, the key is a weak key in ACM. But, the key (30, 40, 10, 20, 80, 50, 60, 70) is not weak because it does not have
any pattern in the above.

Now, Younghee wants to find an efficient method to determine, for a given key, whether it is a weak key or not. Write a program that can help Younghee.

Input

The input consists of T test cases. The number of test cases T is given in the first line of the input file. Each test case starts with a line
containing an integer k, the length of a sequence repressenting a key, 4k5,
000. In the next line, k mutually distinct positive integers are given. There is a single space between the integers, and the integers are between 1 and 100,000, both inclusive.

Output

Print exactly one line for each test case. Print `YES‘ if the sequence is a weak key. Otherwise, print `NO‘.

The following shows sample input and output for three test cases.

Sample Input

3
6
10 30 60 40 20 50
8
30 40 10 20 80 50 60 70
4
1 2 20 9

Sample Output

YES
NO
NO

要求找到4个整数Np、Nq、Nr、Ns(1<= p < q < r < s <= k)s.t. Nq > Ns > Np > Nr or Nq < Ns < Np < Nr。

先看第一种情况,下标第二大的,值最大,而下标第三大的,值最小,下标最小和最大的都插在了中间,确定这个要求后,先想到dfs求解,但是考虑到5000这个数量比较大,怕函数进出栈太慢。

直接枚举四个值时间复杂度又太高了,所以只枚举两个,枚举Ns和Np,然后记录找到Nq和Nr。

用了两个标记数组, l[i][j] 表示下标小于j且值比Ni大的数中最小值的位置,r[i][j] 表示下标大于j且值比Ni小的数中最大值的位置。

最后在枚举判断就完成了第一种情况。第二种情况直接把数组翻转,然后在判断一次就行了。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <stack>
#include <queue>
#include <bitset>
#include <cassert>
#include <cmath>
#include <functional>

using namespace std;

const int maxn = 5005;
int num[maxn], l[maxn][maxn], r[maxn][maxn];
// l[i][j]表示下标小于j且值比Ni大的数中最小值的位置
// r[i][j]表示下标大于j且值比Ni小的数中最大值的位置
int k;

bool solve()
{
	for (int i = 1; i <= k; i++) {
		l[i][0] = 0;
		for (int j = 1; j < i; j++) { // 枚举Nq和Nr,找Np
			if (num[i] >= num[j]) {
				l[i][j] = l[i][j - 1];
			}
			else if (!l[i][j - 1] || num[j] < num[l[i][j - 1]]) {
				l[i][j] = j;
			}
			else {
				l[i][j] = l[i][j - 1];
			}
		}

	}

	for (int i = 1; i <= k; i++) {
		r[i][k + 1] = 0;
		for (int j = k; j > i; j--) {// 枚举Nq和Nr,找Ns
			if (num[i] <= num[j]) {
				r[i][j] = r[i][j + 1];
			}
			else if (!r[i][j + 1] || num[j] > num[r[i][j + 1]]) {
				r[i][j] = j;
			}
			else {
				r[i][j] = r[i][j + 1];
			}
		}
	}

	//i是q,j是r
	for (int i = 1; i <= k; i++) {
		for (int j = i + 1; j <= k; j++) {
			if (!l[j][i - 1] || !r[i][j + 1] || num[i] <= num[j]) {
				continue;
			}
			int p = l[j][i - 1], s = r[i][j + 1];
			if (num[j] < num[p] && num[p] < num[s] && num[s] < num[i]) {
				return true;
			}
		}
	}
	return false;
}

int main()
{
	ios::sync_with_stdio(false);
	int T;
	cin >> T;
	while (T--) {
		cin >> k;
		for (int i = 1; i <= k; i++) {
			cin >> num[i];
		}

		if (solve()) {
			cout << "YES\n";
		}
		else {
			reverse(num + 1, num + k + 1);
			if (solve()) {
				cout << "YES\n";
			}
			else {
				cout << "NO\n";
			}
		}
	}

	return 0;
}
时间: 2024-10-24 10:32:38

UVa - 1618 - Weak Key的相关文章

UVA - 1618 Weak Key(RMQ算法)

题目: 给出k个互不相同的证书组成的序列Ni,判断是否存在4个证书Np.Nq.Nr.Ns(1≤p<q<r<s≤k)使得Nq>Ns>Np>Nr或者Nq<Ns<Np<Nr. 思路: 有两种情况<小.最大.最小.大>.<大.最小.最大.小>,枚举第1个和第4个数,用RMQ查询这两个数之间的最大值和最小值,然后根据给出的条件判断一下就可以了. 看到好多大佬不用RMQ也写出来了,还需要在研究一下. 代码: #include <bit

1618 - Weak Key

一开始自己搞,写了半天还是成了四重循环,虽然没个循环依次递减,而且二分查找,但是依然超时,唉,看来还是太弱啊,思路过于单一. 搜了一个题解,是用递推构造了两个二维数组,利用题目的特点维护了两个变量,然后只需要枚举q和r就可以了. l[i][j]表示下标小于j且值比a[i]大的数中最小的值的下标. r[i][j]表示下标大于j且值比a[i]小的数中最大的值的下标. 我们枚举q和r ,那么显然可以利用r[i][j]找到下标比r大的且值比a[q]小的最大值,也就是s 同理可以用l[i][j]找到p,而

【习题 8-16 UVA - 1618】Weak Key

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 枚举N[q]和N[r]的位置 因为N[q]是最大值,且N[r]是最小值. 且它们是中间的两个. 枚举这两个可以做到不重复枚举. 然后假设我们枚举了q和r的位置分别为i和j (a[i]>a[j] 那么我们接下来需要得到两个东西. 1.在j的右边找到一个尽可能大的且小于a[i]的数字dp[0][i][j]; 2.在i的左边找到一个尽可能小且大于a[j]的数字dp[1][i][j]. 然后判断一下dp[0][i][j]> a[j]

JAVA集合框架

收藏 查看我的收藏 146有用+1 56 编辑 Java,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台的总称.用Java实现的HotJava浏览器(支持Java applet)显示了Java的魅力:跨平台.动态的Web.Internet计算.从此,Java被广泛接受并推动了Web的迅速发展,常用的浏览器现在均支持Java applet.集合框架是为表示和操作集合而规定的一种统一的标准的体系结构.任何集合框架都包含三大块内容:对外的接口.接口的实

5.5 数据结构和算法

1.数据的逻辑结构: 1)线性结构:(只有一个开始结点和一个终端结点) 2)非线性结构:(一个结点有多个前驱结点和后继结点) A: 集合:(元素之间的关系较为松散)                B: 线性结构:(元素之间存在严格的一对一的关系) C: 树形结构:(元素之将存在严格的一对多关系)      D: 网状结构: (元素之间存在多对多关系) 2.数据的存储结构: A:顺序结构   B:连接结构    C:索引结构    D:散列结构 对JAVA的集合的理解是相对于数组.数组是大小固定的

Set,List,Map的区别

Set,List,Map的区别 java集合的主要分为三种类型: Set(集) List(列表) Map(映射) 要深入理解集合首先要了解下我们熟悉的数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),而JAVA集合可以存储和操作数目不固定的一组数据. 所有的JAVA集合都位于 java.util包中! JAVA集合只能存放引用类型的的数据,不能存放基本数据类型. 简单说下集合和数组的区别:(参考文章:<Thinking In Algorithm>03.数据结

Android--list map set 区别

Java集合(list set map)简介 对JAVA的集合的理解是想对于数组,数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),所有的JAVA集合都位于 java.util包中,JAVA集合只能存放引用类型的的数据,不能存放基本数据类型. JAVA集合主要分为三种类型: Set(集) List(列表) Map(映射) Collection 接口 Collection是最基本的集合接口,声明了适用于JAVA集合的通用方法.Set和List都继承了Conllectio

Java-list,set,map的区别

jdk中api的定义 Collection ├----List │ ├----LinkedList │ ├----ArrayList │ └----Vector │ └----Stack └----Set Map ├----Hashtable ├----HashMap ├ ├----LinkedHashMap └----WeakHashMap Set,List,Map的区别 java集合的主要分为三种类型: Set(集) List(列表) Map(映射) 要深入理解集合首先要了解下我们熟悉的数组

对称加密算法之DES介绍

DES(Data Encryption Standard)是分组对称密码算法.DES采用了64位的分组长度和56位的密钥长度,它将64位的输入经过一系列变换得到64位的输出.解密则使用了相同的步骤和相同的密钥.DES的密钥长度为64位,由于第n*8(n=1,2,-8)是校验位,因此实际参与加密的长度为56位,密钥空间含有2^56个密钥. DES算法利用多次组合替代算法和换位算法,分散和错乱的相互作用,把明文编制成密码强度很高的密文,它的加密和解密用的是同一算法. DES算法,是一种乘积密码,其在