Loading

联赛模拟测试33

A.合并集合

区间DP
g[i][j]表示从第i位到第j位中间有多少不重复出现的数字
f[i][j]表示合并i到j能获得的收益之和
特队儿在写的时候
正序遍历挂成零分
原来是没有学习经验
还是要注意遍历方法

B.ZYB建围墙

众所周知,一个合格的OIer不仅要会数奥,物奥,生奥
甚至还要会一点点美术

考试的时候画了好久
打表拿到了\(50pts\)
正解其实也还是找规律
但是考场上没时间往下想了
加上最后\(T4\)没写出来
也没时间回头看\(T2\)
就鸽了
在一圈上没多扩展一层,点数+当前层数
暴力快加到n的时候
再一点一点往上加就行了

C.ZYB和售货机

随便写了个特殊性质\(10pts\)

D.ZYB玩字符串

虽然还是打的暴力
但是对于这个题还是有话要说
毕竟下午改了两节半课
其实思路不很难
考场上就在写了
到现在才调出来
就是暴力枚举要匹配哪个串
然后暴力删除
删完之后再枚举再删除
直到不能删为止
如果全部删完了
那就证明这个串可行
可以作为备用答案
如果没删完,不能直接证明不行
也可能是删的顺序不对
因此
对于整个串
正着枚举删除一遍存答案
倒着枚举删除一遍存答案
比较最优(长度最短,字典序最小)
输出即可

这样能够拿到\(50pts\)的好成绩
那么正确性还是不对的
如上所说
删除的顺序对当前串的判断是有影响的
正着一遍倒着一遍相当于只统计了从第一个开始删除和最后一个开始删除的情况
当然还有可能是从中间开始删除的
这一点的话
其实也可以处理
每次匹配的时候预处理出所有能删除的地方
然后枚举每个地方进行删除
这样的话正确性是能够保障的
但是时间效率暴跌到\(O(2^n)\)
对于现在的数据有点得不偿失
毕竟写的挺累
粘个劳动成果

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

inline int read(){
	int x = 0, w = 1;
	char ch = getchar();
	for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w;
}

const int ss = 700;
const unsigned long long base = 233;
unsigned long long ha1[ss], ha2[ss], power[ss];

char ch[ss], cpy[ss], b[ss], ass[ss];
inline bool check(register char *a, register char *b){
	memcpy(ass, a, sizeof a);
	register int n = strlen(a + 1), len = strlen(b + 1);
	memset(ha2, 0, sizeof ha2);
	for(register int i = 1; i <= len; i++)
		ha2[i] = ha2[i - 1] * base + b[i];
	while(n){
		register bool flag = 0;
		for(register int l = 1; l + len - 1 <= n; l++){
			flag = 0;
			memset(ha1, 0, sizeof ha1);
			for(register int i = 1; i <= n; i++)
				ha1[i] = ha1[i - 1] * base + a[i];
			register int r = l + len - 1;
			register unsigned long long tmp = ha1[r] - ha1[l - 1] * power[r - l + 1];
			if(tmp == ha2[len]){
				flag = 1;
				register int cnt = 0;
				memset(ass, 0, sizeof ass);
				for(register int i = 1; i <= l - 1; i++)
					ass[++cnt] = a[i];
				for(register int i = r + 1; i <= n; i++)
					ass[++cnt] = a[i];
				n -= len;
				memcpy(a, ass, sizeof ass);
				break;
			}
		}
		if(!flag) break;
	}
	if(n) return 0;
	return 1;
}

signed main(){
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout);
	register int T = read();
	power[0] = 1;
	for(register int i = 1; i <= 605; i++)
		power[i] = power[i - 1] * base;
	while(T--){
		string ans1, ans2;
		scanf("%s", ch + 1);
		register int n = strlen(ch + 1);
		memcpy(cpy, ch, sizeof ch);
		register bool flag = 0;
		for(register int len = 1; len <= n; len++){
			if(flag) break;
			for(register int i = 1; i + len - 1 <= n; i++){
				if(flag) break;
				memcpy(ch, cpy, sizeof cpy);
				memset(b, 0, sizeof b);
				register int num = 0;
				for(register int j = i; j <= i + len - 1; j++)
					b[++num] = ch[j];
				if(check(ch, b)){
					flag = 1;
					ans1 = b + 1;
					break;
				}
			}
		}
		memcpy(ch, cpy, sizeof cpy);
		reverse(ch + 1, ch + 1 + n);
		memcpy(cpy, ch, sizeof ch);
		flag = 0;
		for(register int len = 1; len <= n; len++){
			if(flag) break;
			for(register int i = 1; i + len - 1 <= n; i++){
				if(flag) break;
				memcpy(ch, cpy, sizeof cpy);
				memset(b, 0, sizeof b);
				register int num = 0;
				for(register int j = i; j <= i + len - 1; j++)
					b[++num] = ch[j];
				if(check(ch, b)){
					flag = 1;
					ans2 = b + 1;
					break;
				}
			}
		}
		reverse(ans2.begin(), ans2.end());
		if(ans1.size() < ans2.size()) cout << ans1 << endl;
		else if(ans2.size() < ans1.size()) cout << ans2 << endl;
		else cout << min(ans1, ans2) << endl;
	}
}

注意事项

算了写到集锦里面去吧

posted @ 2020-11-19 16:56  Gary_818  阅读(107)  评论(1编辑  收藏  举报