猿辅导2020秋招第三题

小猿有一台打字机,只能打出’A’、‘B’、'C’字符三种。某天小猿打了一段长度为N的字符串1,然后发现可以通过打字机的快捷操作来快速改写字符串。
已知一次快捷操作必须同时改写K个不同的位置的字符,且被改写的字符必须改写字符串,且被改写的字符必须改成打字机可以打出的其他字符。例如,K=2时,“AB"可以被改写成"CA”,也可以被改写为"BC",但不可以被改写为"AA"(必须恰好改写K个字符)或"EF"。
可以请问通过M次快捷操作,能有多少种将字符串1改写为目标字符串的方案?

输入描述: 第一行输入三个整数,N、M、K。
接下来两行输入原始字符串1和目标字符串2。
1<=N<=100 1<=M<=100
0<=K<=N

输出描述:
方案数

示例1

输入
3 2 3
AAA
CCC

输出
1

示例2

输入
2 2 2
AA
AA

输出
4

其实输出是方案数对1000000007取模的结果,不过这里没算;由于没有在实际试题上调试,实际AC率有待商榷,主要思路:把能在M次操作后变为目标字符的位和不能在M次操作后变为目标字符的位的分开;不能在M次操作后变为目标字符又分为两种情况:
(1).目标字符和源字符不同,意味着源字符串不可能在M次操作后变为目标字符,即方案数为0;
(2).目标字符和源字符相同,意味着这位是就是不能在M次操作后变为目标字符,在计算方案数时就可以不管这位了;
之后只要在能在M次操作变为目标字符这些位里计算方案数就好。

先同时遍历两个字符串,找出能在M次操作后变为目标字符的源字符位,并计算该位的方案数,把各个位的方案数push进一个vector里,之后对这个对这个vector计算方案数即可
主要思想是分而治之
假设这个vector有c1,c2,c3,c4,四个字符位的方案数,对应为k1,k2,k3,k4,现在假设同时操作2位,则总方案数位:
(k1+k2+k3)* k4
那么假如是同时操作3位,则总方案数为:
(k1+k2+k3) * k4*k5+(k1+k2) *k3 *k4 + k1 * k2 * k3

我们设从k1,k2,k3,k4,…,kn中抽K位数来操作的方案数的函数为:
F(k1,k2,k3,…kn;K)
假设已经确定抽了最后一个数kn,那么我们就只需要在剩下的k1,k2,k3,k4,…,kn-1个数里抽K-1位来操作
即 F(k1,k2,k3,…,kn-1;K-1) * kn
假设已经确定要抽最后倒数第二个数Kn-1,那么我们就只需要在剩下的k1,k2,k3,k4,…,kn-2个数里抽K-1位来操作
即F(k1,k2,k3,…,kn-2;K-1) * kn-1
假设已经确定要抽最后倒数第三个数Kn-2,那么我们就只需要在剩下的k1,k2,k3,k4,…,kn-3个数里抽K-1位来操作
即F(k1,k2,k3,…,kn-3;K-1) * kn-2

直到(k1,k2,k3,…kn-k)的数目不足抽K位来操作
所以F(k1,k2,k3,…kn;K) = F(k1,k2,k3,…,kn-1;K-1) * kn + F(k1,k2,k3,…,kn-2;K) * kn-1 + … +k1 * k2 * k3*…kn-k

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int tos2(char c1,char& c2,int m,int& count) {
	if (m == 0) {
		if (c1 == c2) {
			count++;
			return count;
		}
		else 
			return 0;
	}
	bool res;
	switch (c1) {
		case 'A':
			tos2('B', c2, m - 1, count);
			tos2('C',c2,m-1,count);
			break;
		case 'B':
			tos2('A', c2, m - 1, count);
			tos2('C', c2, m - 1, count);
			break;
		case 'C':
			tos2('A', c2, m - 1, count);
			tos2('B', c2, m - 1, count);
			break;
	}
	return count;
}

int summr(vector<int>& vec, int len,int k) {
	int sum = 0;
	if (k == 0) return 1;
	if (k == 1) {
		for (int i = len-1; i >=0 ; i--) {
			sum += vec[i];
		}
		return sum;
	}
	else {
		for (int i = len - 1; i >= 0; i--) {
			if (i + 1 < k) break;
			sum += vec[i] * summr(vec, i, k - 1);
		}
	}
	return sum;
}

int main() {
	int n, m, k;
	cin >> n >> m >> k;
	string s1, s2;
	cin >> s1;
	cin >> s2;
	vector<int> s1c;
	for (int i = 0; i < s1.size(); i++) {
		int count = 0;
		if (tos2(s1[i], s2[i], m, count)) {
			s1c.push_back(count);
		}
		else {
			if (s1[i] != s2[i])
				return 0;
		}
	}
	int sum = 0;
	int len = s1c.size();
	sum = summr(s1c,len,k);
	cout << sum << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值