传送门:点击打开链接
题意:小刀和大刀是双胞胎兄弟。今天他们玩一个有意思的游戏。 大刀给小刀准备了一个长度为n的整数序列。小刀试着把这个序列分解成两个长度为n/2的子序列。
这两个子序列必须满足以下两个条件:
1.他们不能相互重叠。
2.他们要完全一样。
如果小刀可以分解成功,大刀会给小刀一些糖果。
然而这个问题对于小刀来说太难了。他想请你来帮忙。(n <= 40)
思路:调整了几天,今天手感好到爆啊,好久没有连编译错误都没有一次性写完的了。
这道题很有意义,n的大小为40,会比较容易想到,如果为20时就可以枚举子集,那么40是不是应该考虑折半的方法。
这题的折半非常有意思,先取前n/2个数字,去枚举所有状态,把前n/2个数字分到两个串中,如果一个串是另一个串的前缀,那么就把非前缀的后面部分插入到hash表中。
再考虑后n/2个数字,枚举所有状态,把后n/2个数字放到两个串中,如果一个串是另一个串的后缀,那么去hash表中查找非后缀部分是否存在,如果存在,那么就是有解了,否则就是无解
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;const int MX = 1e5 + 5;
const int HMAX = 1000007;
const int sed = 131;int n;
int A[100], B[100], S[2][MX];
struct HData {ULL x;int nxt;
} HA[MX];
int Head[HMAX], rear;
void Hash_init() {rear = 0;memset(Head, -1, sizeof(Head));
}
void Hash_add(ULL x) {int h = x % HMAX;for(int i = Head[h]; ~i; i = HA[i].nxt) {if(x == HA[i].x) return;}HA[rear].x = x;HA[rear].nxt = Head[h];Head[h] = rear++;
}
bool Hash_query(ULL x) {int h = x % HMAX;for(int i = Head[h]; ~i; i = HA[i].nxt) {if(x == HA[i].x) return true;}return false;
}int main() {int T; //FIN;scanf("%d", &T);while(T--) {Hash_init();scanf("%d", &n);for(int i = 1; i <= n; i++) {scanf("%d", &A[i]);B[i] = A[i];}sort(B + 1, B + 1 + n);int sz = unique(B + 1, B + 1 + n) - B - 1;for(int i = 1; i <= n; i++) {A[i] = lower_bound(B + 1, B + 1 + sz, A[i]) - B;}int hn = n / 2;for(int s = 0; s < (1 << hn); s++) {int cur[2] = {0, 0}, sign = true;for(int i = 0; i < hn; i++) {int t = s >> i & 1;S[t][++cur[t]] = A[i + 1];if(cur[t] <= cur[t ^ 1] && S[t][cur[t]] != S[t ^ 1][cur[t]]) {sign = false; break;}}if(sign) {ULL x = 0;int id = cur[0] >= cur[1] ? 0 : 1;for(int i = cur[id ^ 1] + 1; i <= cur[id]; i++) {x = x * sed + S[id][i];}Hash_add(x);}}bool ans = false;for(int s = 0; s < (1 << hn); s++) {int cur[2] = {0, 0}, sign = true;for(int i = 0; i < hn; i++) {int t = s >> i & 1;S[t][++cur[t]] = A[n - i];if(cur[t] <= cur[t ^ 1] && S[t][cur[t]] != S[t ^ 1][cur[t]]) {sign = false; break;}}if(sign) {ULL x = 0;int id = cur[0] >= cur[1] ? 0 : 1;for(int i = cur[id]; i != cur[id ^ 1]; i--) {x = x * sed + S[id][i];}if(Hash_query(x)) {ans = true; break;}}}printf("%s\n", ans ? "Good job!!" : "What a pity!");}return 0;
}