C. Flexible String(DFS组合数学选出具体种类)

Problem - C - Codeforces

 你有一个字符串a和一个字符串b,两个字符串的长度都是n。在字符串a中最多有10个不同的字符。你还有一个集合Q。最初,集合Q是空的。您可以对字符串应用以下操作任意次数:选择索引i (1 < i< n)和小写英文字母c,将a添加到集合Q中,然后将a替换为c。例如,设字符串a为“abecca”。我们可以做以下操作:在第一个操作中,如果你选择i = 3和c = x,字符as = e将被添加到集合Q中。因此,集合Q将是{e},字符串a将是"abxcca"。在第二个操作中,如果你选择i=6和c=s,字符a6=a将被添加到集合Q中。因此,集合Q将是{e, a},字符串a将是"abxccs"。您可以对a应用任意数量的操作,但最终,集合Q应该包含最多k个不同的字符。在这个约束条件下,你必须最大化整数对(l, r)的数量(1 <l <r< n),使得a[l, r] = b[l, r]。这里,s[l, r]表示字符串s的子字符串,从索引I(含)开始,到索引r(含)结束。输入每个测试包含多个测试用例。第一行包含测试用例的数量t (1 < t < 104)。测试用例的描述是流畅的。第一行包含两个整数n和k (1 <n <105,0<k<10)——两个字符串的长度和不同Q的极限。集合中的字符第二行是长度为n的字符串a。字符串a中最多可以包含10个不同的字符。最后一行包含长度为n的字符串b。字符串a和b都只包含小写英文字母。所有测试用例的n和不超过105。输出对于每个测试用例,在一行中打印一个整数,即满足约束的最大对数(I, r)。例子

input

Copy

 

6

3 1

abc

abd

3 0

abc

abd

3 1

xbb

xcd

4 1

abcd

axcb

3 10

abc

abd

10 3

lkwhbahuqa

qoiujoncjb

output

Copy

6
3
6
6
6
11

请注意在第一种情况下,我们可以选择索引i = 3,并将其替换为字符c = d。所有可能的对(l, r)都是有效的。在第二种情况下,我们不能进行任何操作。3对有效的(l, r)是:1. A [1,1] = b[1,1] = " A ",2. A [1,2] = b[1,2] = "ab",3.A [2,2] = b[2,2] = "b"。在第三种情况下,我们可以选择索引2和索引3,并分别将它们替换为字符c和d。最终的集合Q将是{b},其大小为1,满足k的值。所有可能的对(l, r)都是有效的。

题解:
根据题中所给数据发现可供我们修改的字母种类k只有十,并且原来字符串中的字母种类cnt也只有10

1.如果k >= cnt

a可以和b变的一样,所以l,r的对数是n*(n-1)/2 + n

2.如果k < cnt

我们发现选取的种类数是从十种里面选五个,最多只要252种情况

而n的只有1e5,所以直接DFS找的所以情况,取最大值即可

关键是如何DFS

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
using namespace std;
#define int long long
const int N = 6e5 + 10;
string s;
int n,k;
int vis[30];
map<char,int> ff;
int ans = 0,cnt = 0;
string a,b;
void dfs(int i1,int cnt1)
{
	if(i1 > cnt)
	{
		if(cnt1 == k)
		{
			int sum = 0;
			int t = 0;
			for(int i = 0;i < n;i++)
			{
				if(a[i] == b[i]||vis[a[i] - 'a'])
				sum++;
				else
				t += sum*(sum + 1)/2,sum = 0;
				
			}
			t += sum*(sum + 1)/2;
			ans = max(ans,t);
		}
	}
	else
	{
		dfs(i1 + 1,cnt1);
		vis[s[i1] - 'a'] = 1;//第i1个字母拿过了
		if(cnt1 < k)
		dfs(i1 + 1,cnt1 + 1);//如果cnt1 < k要修改的字母种类还不够
		vis[s[i1] - 'a'] = 0;
	}
}
void solve()
{
	cin >> n >> k;
	cin >> a >> b;
	map<char,int> f;
	memset(vis,0,sizeof vis);
	cnt = 0;
	ans = 0;
	s = "";
	for(auto c:a)
	{
		if(!f[c])
		{
			s = s + c;
			f[c] = 1;
			cnt++;
		}
	}
	if(cnt <= k)
	{
		cout << n*(n+1)/2 <<"\n";
		return ;
	}
	s = " " + s;
	dfs(1,0);
	cout << ans <<"\n";
}
signed main()
{
	int t = 1;
	cin >> t;
	while(t--)
	{
		solve();
	} 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值