字符串思维题练习 DAY2(CF1045I ,CF 1295C , CF 1348C)

字符串思维题练习 DAY2

CF 1045 I. Palindrome Pairs(哈希)

Problem - I - Codeforces

大意:给出 n 个字符串 , 找出满足以下性质的字符串对(i, j)满足si + sj 的一个排列是回文 , 求对数。

思路:考虑 si + sj 的一个排列是回文 , 转化到奇偶性上 , 即:si + sj 的所有字母出现次数都是偶数 或 其中一个出现次数是奇数其余全是偶数。 对于奇偶性 , 考虑哈希 , 把字符串哈希成一个26位的二进制数 , 从前往后计数即可 , 要注意的是 , 开数组会MLE , 用 unorderedmap 代替数组即可。

#include
using namespace std;
#define fi first
#define se second
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define int long long
const int INF = 9e18;
const int N = 2e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int,int>PII;

int n , res;
int num[30];
string s;
unordered_map<int , int>cnt;

signed main(){

	IOS
	cin >> n;
	for(int i = 1 ; i <= n ; i ++) {
		cin >> s;
		for(int j = 0 ; j < 30 ; j ++) num[j] = 0;
		for(int j = 0 ; j < (int)s.size() ; j ++) {
			num[s[j] - 'a'] += 1;
		}
		int now = 0;
		for(int j = 0 ; j < 26 ; j ++) {
			now += (1 << j) * (num[j] % 2 == 1);
		}
		res += cnt[now];
		for(int j = 0 ; j < 26 ; j ++) {
			int bit = now >> j & 1;
			int val = 0;
			if(bit == 1) val = now - (1 << j);
			else val = now + (1 << j);
			res += cnt[val];
		}
		cnt[now] += 1;
	}
	
	cout << res << "\n";

	return 0;
}
//freopen("文件名.in","r",stdin);
//freopen("文件名.out","w",stdout);

CF 1295 C.Obtain The String(二分)

Obtain The String - 洛谷

大意:给出两个字符串 s 和 t , 一个空串 z , 每次往 z 的末尾加一个 s 的子序列 , 问至少多少次操作能变成 t。不可能输出 -1.

思路:对于 -1 的情况 , 当 t 中存在 s 中不存在的字符 , 即为 -1 的情况 , 考虑如何求这个最小的次数。最暴力的方法就是对 t 暴力扫描 , 最坏复杂度O(|s||t|) , 显然不能接受 , 考虑优化 , 对于每一个字母 , 我们显然只需要搜索这些字母在 s 串中出现的位置中找一个合理的位置即可 , 而不需要去搜索其余不等于其的字母 , 考虑预处理出每个字母在 s 中出现的位置 , 每次匹配二分查找合理位置即可。

复杂度 ( n l o g n ) 复杂度(nlogn) 复杂度(nlogn)

#include
using namespace std;
#define fi first
#define se second
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define int long long
const int INF = 9e18;
const int N = 2e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int,int>PII;

int t ; 

string s , x;

signed main(){

	IOS
	cin >> t;
	
	while(t --) {
		map<char , bool>vis;
		cin >> s >> x;
		for(auto k : s) vis[k] = 1;
		bool tag = 0;
		for(auto k : x) if(!vis[k]) tag = 1;
		map<char , vector<int>>mp;
		if(tag) {
			cout << "-1\n";
			continue;
		} else {
			s = '?' + s;
			int n = s.size();
			int pre = -1 , res = 1;
			for(int i = 1 ; i <= n ; i ++) mp[s[i]].push_back(i);
			for(int i = 0 ; i < (int)x.size() ; i ++) {
				char now = x[i];
				int id = 0 , pos = 0; 
				if(upper_bound(mp[now].begin() , mp[now].end() , pre) == mp[now].end()) {
					id = upper_bound(mp[now].begin() , mp[now].end() , -1) - mp[now].begin();
					pre = mp[now][id];
					res += 1;
				} else {
					id = upper_bound(mp[now].begin() , mp[now].end() , pre) - mp[now].begin();
					pos = mp[now][id];
					pre = pos;
				}
				 
			}
			cout << res << "\n";
		}
	}

	return 0;
}
//freopen("文件名.in","r",stdin);
//freopen("文件名.out","w",stdout);

CF 1348 C. Phoenix and Distribution(思维)

Problem - C - Codeforces

大意:把长度为 n 的字符串分成 k 部分 , 最小化最大字典序的字符串并输出。

考虑:先对字符串排序 , 肯定要先贪心的放小的。分情况讨论 , 每个部分先放一个 , 如果每一部分的第一个字母不全相同 , 那么答案就是最后一部分的那个字母 , 否则讨论剩下没分的种类是否大于2 , 如果大于 1 , 全放在第一个类中 , 第一个类即是答案 , 如果等于 1 , 那么显然均分。

#include
using namespace std;
#define fi first
#define se second
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define int long long
const int INF = 9e18;
const int N = 2e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int,int>PII;

int t , n , k;
string s;

signed main(){

	IOS
	cin >> t;
	
	while(t --) {
		cin >> n >> k;
		vector<string>ve(k + 1);
		cin >> s;
		map<char , int>mp;
		int type = 0;
		for(int i = 0 ; i < (int)s.size() ; i ++) {
			mp[s[i]] += 1;
			if(mp[s[i]] == 1) type += 1;
		}
		sort(s.begin() , s.end());
		s = '?' + s;
		if(s[1] != s[k]) {
			cout << s[k] << "\n";
		} else {
			for(int i = 1 ; i <= k ; i ++) {
				ve[i] += s[i];
				mp[s[i]] -= 1;
				if(mp[s[i]] == 0) type -= 1;
			}
			if(type == 1) {
				int cnt = (n - k) / k + 1 * ((n - k) % k != 0); 
				for(int i = 1 ; i <= cnt ; i ++) {
					ve[1] += s[k + 1];
				}
			} else { 
				for(int i = k + 1 ; i <= n ; i ++) ve[1] += s[i];
			}
			cout << ve[1] << "\n";
		}
	}

	return 0;
}
//freopen("文件名.in","r",stdin);
//freopen("文件名.out","w",stdout);

你可能感兴趣的:(算法)