C. Flexible String codeforces1778C

Problem - C - Codeforces

题目大意:有两个长度为n的字符串a,b,每次操作可以选出字母表中的一个字母,并使a中所有该字母分别变成任意的字母,最多操作k次,问最多有多少个数对l,r使a[l],a[r]之间的满足a=b的子串数量最多

1<=n<=1e5;0<=k<=10,a中最多有10个不同的字母

思路:因为操作的次数越多,答案的数量肯定不会变小,所以从a中选出的不同字母的数量k应为min(k,m(a中不同字母数)),然后我们发现从最多10个字母中选k个字母最多只有C(5,10)=252种可能,那么我们对每一种选择出来的字母,遍历字符串,替换相应字符并统计即可。

对于从m个字母中选择k个字母,可以用递归的方法,对于m个字母中的第i个,先考虑不选这个字母,之后回溯时考虑选这个字母,再回溯时,将其置回不选择的状态即可。如果当前已经遍历到第m个字母,且选择的字母数等于k,就统计答案,否则直接回溯。

对于确定选取的字母后遍历a,我们只要找到a=b的位置就计数,直到不满足a=b,就加上计数*(计数+1)/2,每次统计答案后取最大值即可

//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans = 0;
string s1, s2;
string app;
int n, k;
bool vis[30];
int len;
void count(int itap, int cnt)
{//遍历到了app字符串的第itap个字母,当前已选择cnt个字母
	if (cnt > k)
		return;//选择的超过k个,不合法
	if (itap == len)
	{//所有字母已经遍历结束
		if (cnt == k)
		{//如果选择的字母数正好等于k,统计答案
			ll temp = 0;
			ll now = 0;//符合条件的区间长度
			for (int i = 0; i < n; i++)
			{
				if (s1[i] == s2[i] || vis[s1[i] - 'a'])
				{//本来就等于,或者可以修改
					now++;
				}
				else
				{
					temp += now * (now + 1) / 2;//区间结束,统计答案
					now = 0;
				}
			}
			temp += now * (now + 1) / 2;//数组结束也要统计
			ans = max(ans, temp);
		}
		return;
	}
	count(itap + 1, cnt);//不选当前字母
	vis[app[itap] - 'a'] = 1;//选当前字母
	count(itap + 1, cnt + 1);
	vis[app[itap] - 'a'] = 0;//回溯后重置
}
int main()
{
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--)
	{		
		cin >> n >> k;		
		cin >> s1 >> s2;
		unordered_set<char>se;//记录都有哪些不同字母
		for (int i = 0; i < n; i++)
		{
			se.insert(s1[i]);
		}
		app.clear();
		for (unordered_set<char>::iterator it=se.begin(); it != se.end(); it++)
		{
			app.push_back(*it);//用字符串记录不同字母,便于遍历
		}
		len = app.length();
		ans = 0;
		k = min(k, len);
		memset(vis, 0, sizeof vis);
		count(0, 0);
		cout << ans << endl;
	}
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timidcatt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值