SRM 550

矩阵乘法

状态表示为[i][j][k]表示这一个串中已经匹配好的有i个,差两步的有j个,差一步的有k个,显然i+j+k=len。

len最多11,所以状态数最多不到80

构造矩阵就是(i,j,k)->(i-1,j+1,k) ,有i个选择,要乘以i,另外两个转移也是一样的


然后就是一共能走几步的问题,统计一下最少步数复原要走几步,花费cost。能走的步数就是  复原的步数+3*((最多花费-花费)/走三步的花费)

然后矩阵乘法就可以了。


#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>

using namespace std;

class ConversionMachine {
public:
	int countAll(string, string, vector<int> , int);
};
long long pmod = 1000000007;
int id[12][12][12];
int rid[100][3];
int ed;
long long a[105][105], tmp[105][105], tr[105][105];
void mul(long long a[][105], long long b[][105]) {
	int i, j, k;
	memset(tmp, 0, sizeof(tmp));
	for (i = 0; i < ed; ++i) {
		for (j = 0; j < ed; ++j) {
			for (k = 0; k < ed; ++k) {
				tmp[i][j] += a[i][k] * b[k][j];
				tmp[i][j] %= pmod;
			}
		}
	}
	for (i = 0; i < ed; ++i) {
		for (j = 0; j < ed; ++j)
			a[i][j] = tmp[i][j];
	}
}

int ConversionMachine::countAll(string word1, string word2, vector<int> costs,
		int maxCost) {
	int i, j, k, n = word1.size();
	int ii, jj, kk;
	long long cost = 0;
	int step = 0;
	ii = jj = kk = 0;
	for (i = 0; i < word1.size(); ++i) {
		if (word1[i] == 'a') {
			if (word2[i] == 'b') {
				cost += costs[0];
				step++;
				kk++;
			} else if (word2[i] == 'c') {
				cost += costs[0] + costs[1];
				step += 2;
				jj++;
			} else
				ii++;
		}
		if (word1[i] == 'b') {
			if (word2[i] == 'c') {
				cost += costs[1];
				step++;
				kk++;
			} else if (word2[i] == 'a') {
				cost += costs[1] + costs[2];
				step += 2;
				jj++;
			} else
				ii++;
		}
		if (word1[i] == 'c') {
			if (word2[i] == 'a') {
				cost += costs[2];
				step++;
				kk++;
			} else if (word2[i] == 'b') {
				cost += costs[2] + costs[0];
				step += 2;
				jj++;
			} else
				ii++;
		}
	}
	if (maxCost < cost)
		return 0;
	step += ((maxCost - cost) / (costs[0] + costs[1] + costs[2])) * 3;
	ed = 0;
	for (i = 0; i <= n; ++i) {
		for (j = 0; i + j <= n; ++j) {
			k = n - i - j;
			id[i][j][k] = ed;
			rid[ed][0] = i;
			rid[ed][1] = j;
			rid[ed][2] = k;
			ed++;
		}
	}
	memset(a, 0, sizeof(a));
	ed++;
	for (i = 0; i < ed; ++i)
		a[i][i] = 1;
	memset(tr, 0, sizeof(tr));
	for (i = 0; i < ed - 1; ++i) {
		int pi, pj, pk;
		pi = rid[i][0];
		pj = rid[i][1];
		pk = rid[i][2];
		if (pi > 0)
			tr[i][id[pi - 1][pj + 1][pk]] += pi;
		if (pj > 0)
			tr[i][id[pi][pj - 1][pk + 1]] += pj;
		if (pk > 0)
			tr[i][id[pi + 1][pj][pk - 1]] += pk;
	}
	tr[ed - 1][ed - 1] = 1;
	tr[ed - 1][id[ii][jj][kk]] = 1;
	step++;
	while (step) {
		if (step & 1)
			mul(a, tr);
		mul(tr, tr);
		step >>= 1;
	}
	return a[ed - 1][id[n][0][0]];
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值