ttt学字符串

题目大意

大法师ttt 最近在学习字符串,有一天他看到魔力xtx左手拿着A字符串,右手拿着B字符串,两个字符串的长度都是一样的,而且都由abc三种字符构成,大法师ttt的灵力值为C,现在告诉你 a变b b变c以及c变a分别需要消耗的灵力值(其他变换是不存在的),问你在ttt的灵力值范围内最多能有多少种不同的方案可以从xtx的左手串变换到xtx的右手串

输入格式:

前两行输入两个长度相同的字符串 ,第一个串表示左手串,第二个串表示右手串,右手串不能变
第三行输入三个整数分别代表转换的代价cost_ab cost_bc cost_ca 
第四行输入一个整数表示ttt的灵力值

输出格式:

对于每组数据输出一个数,表示答案

答案为有序的合法操作序列数对1e9+7取模,

样例输入:

a
a
1 2 3
12

样例输出:

3

样例解释:

第一种方案:不花代价已经可以达成目的 
第二种方案:花费6的代价从a -> b -> c -> a 
第三种方案 : 第二种方案重复一遍

数据范围:

n 为字符串长度

  • 30%, n <= 5, max(cost_ab, cost_bc, cost_ca) <= 5, C <= 20
  • 60%, n <= 5, max(cost_ab, cost_bc, cost_ca) <= 100, C <= 1000
  • 100%, n <= 11, max(cost_ab, cost_bc, cost_ca) <= 100, C <= 1000000000

时间限制:

1000 ms

空间限制:

32 MB

DP+矩阵快速幂

60分:

记$dp[i][j][k]$表示用了i次魔法之后的字符串A与字符串B相同的有$i$个,可以通过一次变化得到相同的有$j$个

$n$为字符串的长度

那么可以得到通过两次变化的有$n-i-j$个

那么一次魔法可以有3种选择:改相同的,改还有一次变化的,改还有两次变化的

转移方程为

$dp[i][j][k]=dp[i-1][j-1][k+1]*(k+1)+dp[i-1][j][k-1]*(n-j-k+1)+dp[i-1][j+1][k]*(j+1)$

那么现在要考虑这些状态是否可行

先处理出将字符串A变为字符串B的最小代价是多少

因为在改成相同之后,在进行变化需要3次的操作

那么可以算出最大的操作步数$step$

那么答案为$\sum_{i=0}^{step}dp[i][n][0]$

 1 #include <bits/stdc++.h>
2 #define mod 1000000007
3 #define ll long long
4 using namespace std;
5 ll ab,bc,ca,C,dp[1100][7][7];
6 ll t0,t1,n,step,cost,tot,ans;
7 string a,b;
8 int main()
9 {
10 cin>>a>>b;
11 scanf("%lld%lld%lld%lld",&ab,&bc,&ca,&C);
12 tot=ab+bc+ca;
13 for (ll i=0;i<(ll)a.size();i++)
14 {
15 if (a[i]==b[i])
16 t0++;
17 else
18 {
19 if (a[i]=='c' && b[i]=='a')
20 t1++;
21 if (a[i]=='b' && b[i]=='c')
22 t1++;
23 if (a[i]=='a' && b[i]=='b')
24 t1++;
25 }
26 }
27 for (ll i=0;i<(ll)a.size();i++)
28 {
29 if (a[i]==b[i])
30 continue;
31 if (a[i]=='a' && b[i]=='b')
32 cost+=ab,step++;
33 if (a[i]=='a' && b[i]=='c')
34 cost+=ab+bc,step+=2;
35 if (a[i]=='b' && b[i]=='c')
36 cost+=bc,step++;
37 if (a[i]=='b' && b[i]=='a')
38 cost+=bc+ca,step+=2;
39 if (a[i]=='c' && b[i]=='a')
40 cost+=ca,step++;
41 if (a[i]=='c' && b[i]=='b')
42 cost+=ca+ab,step+=2;
43 }
44 if (cost>C)
45 {
46 printf("0\n");
47 return 0;
48 }
49 step+=3*((C-cost)/tot);//计算最大步数
50 dp[0][t0][t1]=1;//初始状态
51 n=(ll)a.size();
52 for (ll i=1;i<=step;i++)
53 {
54 for (ll j=0;j<=n;j++)
55 {
56 for (ll k=0;k<=n;k++)
57 {
58 if (j+k>n)
59 break;
60 if (j>0 && k<n)
61 dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k+1]*(k+1)%mod)%mod;
62 if (k>0)
63 dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k-1]*(n-j-k+1)%mod)%mod;
64 if (j<n)
65 dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+1][k]*(j+1)%mod)%mod;
66 }
67 }
68 }
69 for (ll i=0;i<=step;i++)
70 ans=(ans+dp[i][n][0])%mod;//累加答案
71 printf("%lld\n",ans);
72 }

100分:

可以发现这个转移方程可以用矩阵优化

在矩阵中只要记录前一层的dp值即可

并填入相应的转移矩阵$tr$

但由于答案是$dp[i][n][0]$的前缀和,需要处理出每个$dp[i][n][0]$

记初始矩阵为$f$

那么需要处理的矩阵为

$f+f*tr+f*tr^{2}+...+f*tr^{step}$

这是等比矩阵求和的问题

详解

转移即可

  1 #include <bits/stdc++.h>
2 #define mod 1000000007
3 #define ll long long
4 using namespace std;
5 ll ab,bc,ca,C,id[15][15][15];
6 ll t0,t1,n,step,cost,tot,ans,cnt;
7 string a,b;
8 struct node
9 {
10 ll n,num[300][300];
11 void init()
12 {
13 for (ll i=1;i<=n;i++)
14 num[i][i]=1;
15 }
16 void prepare()
17 {
18 for (ll i=1;i<=n;i++)
19 {
20 for (ll j=1;j<=n;j++)
21 num[i][j]=0;
22 }
23 }
24 void print()
25 {
26 for (ll i=1;i<=n;i++)
27 {
28 for (ll j=1;j<=n;j++)
29 printf("%lld ",num[i][j]);
30 printf("\n");
31 }
32 }
33 }tr,f;
34 node A;
35 node operator * (node a,node b)
36 {
37 node c;
38 c.n=a.n;
39 c.prepare();
40 for (ll i=1;i<=a.n;i++)
41 {
42 for (ll j=1;j<=a.n;j++)
43 {
44 for (ll k=1;k<=a.n;k++)
45 {
46 c.num[i][j]=(c.num[i][j]+a.num[i][k]*b.num[k][j])%mod;
47 }
48 }
49 }
50 return c;
51 }
52 node m_pow(node a,ll b)
53 {
54 node c;
55 c.n=a.n;
56 c.prepare();
57 c.init();
58 while (b>0)
59 {
60 if (b&1)
61 c=c*a;
62 b>>=1;
63 a=a*a;
64 }
65 return c;
66 }
67 int main()
68 {
69 cin>>a>>b;
70 scanf("%lld%lld%lld%lld",&ab,&bc,&ca,&C);
71 tot=ab+bc+ca;
72 for (ll i=0;i<(ll)a.size();i++)
73 {
74 if (a[i]==b[i])
75 t0++;
76 else
77 {
78 if (a[i]=='c' && b[i]=='a')
79 t1++;
80 if (a[i]=='b' && b[i]=='c')
81 t1++;
82 if (a[i]=='a' && b[i]=='b')
83 t1++;
84 }
85 }
86 for (ll i=0;i<(ll)a.size();i++)
87 {
88 if (a[i]==b[i])
89 continue;
90 if (a[i]=='a' && b[i]=='b')
91 cost+=ab,step++;
92 if (a[i]=='a' && b[i]=='c')
93 cost+=ab+bc,step+=2;
94 if (a[i]=='b' && b[i]=='c')
95 cost+=bc,step++;
96 if (a[i]=='b' && b[i]=='a')
97 cost+=bc+ca,step+=2;
98 if (a[i]=='c' && b[i]=='a')
99 cost+=ca,step++;
100 if (a[i]=='c' && b[i]=='b')
101 cost+=ca+ab,step+=2;
102 }
103 if (cost>C)
104 {
105 printf("0\n");
106 return 0;
107 }
108 n=(ll)a.size();
109 step+=3*((C-cost)/tot);
110 for (ll i=0;i<=n;i++)
111 {
112 for (ll j=0;j<=n;j++)
113 {
114 for (ll k=0;k<=n;k++)
115 {
116 if (i+j+k!=n)
117 continue;
118 cnt++;
119 id[i][j][k]=cnt;
120 if (i==t0 && j==t1)
121 f.num[1][cnt]=1;//填入初始矩阵
122 }
123 }
124 }
125 for (ll i=0;i<=n;i++)//根据DP转移方程填入转移矩阵
126 {
127 for (ll j=0;j<=n;j++)
128 {
129 for (ll k=0;k<=n;k++)
130 {
131 if (i+j+k!=n)
132 continue;
133 if (i>0 && j<n)
134 tr.num[id[i-1][j+1][k]][id[i][j][k]]=j+1;
135 if (j>0 && k<n)
136 tr.num[id[i][j-1][k+1]][id[i][j][k]]=k+1;
137 if (i<n && k>0)
138 tr.num[id[i+1][j][k-1]][id[i][j][k]]=i+1;
139 }
140 }
141 }
142 f.n=tr.n=cnt;
143 A.n=cnt*2;//计算等比矩阵求和
144 A.prepare();
145 for (ll i=1;i<=tr.n;i++)
146 {
147 for (ll j=1;j<=tr.n;j++)
148 A.num[i][j]=A.num[i][j+tr.n]=tr.num[i][j];
149 }
150 for (ll i=tr.n+1;i<=2*tr.n;i++)
151 {
152 for (ll j=tr.n+1;j<=2*tr.n;j++)
153 {
154 if (i==j)
155 A.num[i][j]=1;
156 }
157 }
158 A=m_pow(A,step);
159 for (ll i=1;i<=tr.n;i++)
160 {
161 for (ll j=tr.n+1;j<=2*tr.n;j++)
162 tr.num[i][j-tr.n]=A.num[i][j];
163 }
164 f=f*tr;
165 if (t0==n && t1==0)
166 f.num[1][id[n][0][0]]++;
167 printf("%lld\n",f.num[1][id[n][0][0]]);
168 }

  

XJOI NOIP501/511训练22 ttt学字符串的更多相关文章

  1. Java实现蓝桥杯VIP算法训练 奇变的字符串

    试题 算法训练 奇变的字符串 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 将一个字符串的奇数位(首位为第0位)取出,将其顺序弄反,再放回原字符串的原位置上. 如字符串" ...

  2. [c/c++] programming之路(22)、字符串(三)——字符串封装

    项目结构 头文件.h #include<stdio.h> #include<stdlib.h> #include<string.h> //字符串封装,需要库函数 / ...

  3. Java从0开始学——字符串

    #,java中的字符串是不可变的: #,比较两个字符串是不是相等,不能用==,因为那只能确认他们是否指向了同一个字符串对象: #,空串和null是不同的: #,代码点和代码单元     #,代码点表示 ...

  4. asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

    一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json ...

  5. XJOI网上同步训练DAY6 T2

    思路:记得FJ省队集训好像有过这题,可是我太弱了,根本不懂T_T #include<cstdio> #include<iostream> #include<cmath&g ...

  6. XJOI网上同步训练DAY6 T1

    思路:考试的时候直接想出来了,又有点担心复杂度,不过还是打了,居然是直接A掉,开心啊. 我们发现,Ai<=7,这一定是很重要的条件,我们考虑状态压缩,去枚举路径中出现了哪些数字,然后我们把原来n ...

  7. XJOI网上同步训练DAY5 T1

    思路:考虑得出,最终的集合一定是gcd=1的集合,那么我们枚举n个数中哪个数必须选,然后把它质因数分解,由于质数不会超过9个,可以状态压缩,去得出状态为0的dp值就是答案. #include<c ...

  8. XJOI网上同步训练DAY5 T3

    就是对于一个数,我们去考虑把t*****减到(t-1)9999*的代价. #include<cstdio> #include<cmath> #include<algori ...

  9. XJOI网上同步训练DAY3 T2

    考试的时候已经想出来怎么做了,但是没有时间打了T_T 思路:我们考虑将询问以lim排序,然后树链剖分,把边作为线段树的节点,然后随着询问lim的增大,改变线段树中节点的信息,然后每次询问我们用树链剖分 ...

随机推荐

  1. Jmeter之『如果(If)控制器』

    判断方法 ${__jexl3("${projectName}"=="${targetDir}",)} ${__groovy("${projectNam ...

  2. iPhone手机越狱-逆向砸壳-代码注入

    iPhone手机越狱 逆向砸壳 代码注入 工具下载 操作越狱 安装待逆向应用(app) 使用OpenSSH连接手机 找到应用二进制文件地址 找到应用document沙盒地址 拷贝砸壳工具(dumpde ...

  3. 推荐Java字节码解析工具classpy

    Classpy Classpy is a GUI tool for investigating Java class file, Lua binary chunk, Wasm binary code, ...

  4. Scala小记(一)

    Scala小记----初识Scala 一,什么是Scale? Scala是一门面向对象的,使用JVM运行的函数式编程语言,(函数式编程语言:指的就是那些将方法或者说是函数来作为参数 进行传递的编程语言 ...

  5. C# 软件版本号

    如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! --------------------------- ...

  6. ansible-任务控制tags

    1. ansible-任务控制tags介绍        如果你有一个大型的剧本,那么只能运行它的特定部分而不是在剧本中运行所有内容可能会很有用.因此,Ansible支持"tags:&quo ...

  7. php中 ob_函数 例:ob_start();用法

    ob,输出缓冲区,是output buffering的简称,而不是output cache.ob用对了,是能对速度有一定的帮助,但是盲目的加上ob函数,只会增加CPU额外的负担 ob的基本原则:如果o ...

  8. Redis GEO 功能使用场景

    本文来源:https://www.dazhuanlan.com/2020/02/05/5e3a0a3110649/ 背景 前段时间自己在做附近直播相关业务,其中有一个核心的点就是检索用户附近的主播,也 ...

  9. python练习三角形,99乘法

    #方案一:# result=0# #列# for i in range(1,10):# #行# for j in range(1,i+1):# result=i*j# print('%d*%d=%d' ...

  10. pytest文档57-计算单元测试代码覆盖率(pytest-cov)

    前言 我们在做测试的时候,经常遇到领导的灵魂拷问:你的测试用例覆盖率是多少,达到100%了么?你如何保证你的测试质量? 测试用例的覆盖率如何统计呢,如何知道开发的代码,我们都测到了,不会存在漏测的情况 ...