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 (N1, N2,..., Nk) as
a key. Younghee found that weak keys in ACM have the following two special patterns:
There are four integers Np, Nq, Nr, Ns(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; }