<span style="font-family: 'Microsoft YaHei'; font-size: 18px; background-color: rgb(255, 255, 255);">题目描述:</span>
字符之间形状都有一个相似程度。例如“l”和“i”, “a”和“o”的相似度高,而“x”和“m”的相似度就低。我们定义字符间的形状差异度为1~5等五个等级。相似度高的字符对的差异度低。反之,相似度低的字符对的差异度高。注意,我们规定相同的字符之间的差异度为1!
以此为基础,我们可以定义一个单词的差异度,即:相邻字符之间的差异度之和。
例如,我们规定“e”和“l”的差异度是3,“l”和“y” 的差异度是2,“i”和“l”的差异度是1。这样单词“elly”的差异度为: 3 + 1 + 2 = 6(记住相同字符之间的差异度是1)。单词“lily”的差异度是4,而单字符单词“i”的差异度是1。长的单词的差异度不一定比短的单词的大。例如,“lilii”的差异度仅为4,而“elle”的则有7。但是,一个单词每增加一个字符就至少会增加差异值1。
我们想知道,当给定单词差异度的最大值N时,会有多少个单词的差异度小于等于N呢?
样例输入:
20 10 e l 3 e o 1 o n 2 o r 4 r a 4 i n 5 e n 2 n t 3 t w 3 w i 5
样例输出:
470059518
思路:
先orz 全能神syk的题解……
这是一道矩阵加速的题目,差异值仅存在于相邻的两个字母之间,于是
转换题目:
有26个点,每两个点之间都有一条路径(完全图),给出其中几条路径的长度(length<=5),没有给出的路径默认为1,求该图中长度小于N的路径条数。
基数矩阵(mtx)的构造方法:
设字母i与字母j的差异值为d[i][j],因为矩阵的经典模型之一【限定路径长度求两点之间的路径数】中控制的是路径条数(也可以是路径长度,条件是所有路径长度为1),而这里差异值基本上都>1,不pre()好像没有什么常人的方法控制差异值的大小。于是将每个节点虚拟成一条短链5个节点(见代码),则mtx[i][j+26*(d-1)]=1,而每个mtx[j+26*d][j+26*(d-1)]=1,中间平白无故的多出了d条路径,这样就成功将差异值转化为路径了只有当指数k>=d时i才有可能到达j。
还有一个问题就是,没有严格规定长度必须为N,而是小于N,解决方案:虚拟一个0节点,到每个字母的路径长度为1。但是这样计算的话一旦0节点在路径中的位置不同,计算的时候条数就会++(实际上是不会的,如{_A_B_C}与{_AB_C},因为0节点在最后都不会显示出来,真正起作用的是0节点的个数而非位置),为了避免这种情况,集中将0节点放在开头(0节点可以到0节点和任意节点,任意节点不能到0节点)。
最后枚举起点和终点计算条数。
最后提供一个在syk题解中发现的一个小数据:
1 1 a b 2
700
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long int
const int mod=1000000007;
const int maxn=26*5;
const int maxm=26;
using namespace std;
ll n;
int x;
char op[10];
bool vis[maxm+5][maxm+5];
struct Matrix
{
int e[maxn+5][maxn+5];
}mtx;
void pre()
{
for(int i=1;i<=26;i++)
for(int j=1;j<=4;j++)
mtx.e[i+26*j][i+26*(j-1)]=1;
}
void mul(Matrix a,Matrix b,Matrix &ret)
{
memset(ret.e,0,sizeof(ret.e));
for(int i=0;i<=maxn;i++)
for(int j=0;j<=maxn;j++)
for(int k=0;k<=maxn;k++)
{
ret.e[i][j]=((ll)ret.e[i][j]+(ll)a.e[i][k]*b.e[k][j])%mod;
}
}
void pow(Matrix a,ll b,Matrix &res)
{
for(int i=1;i<=maxn;i++)
res.e[i][i]=1;
while(b)
{
if(b&1)mul(a,res,res);
mul(a,a,a);
b>>=1;
}
}
int main()
{
scanf("%I64d%d\n",&n,&x);
pre();
for(int i=1;i<=x;i++)
{
gets(op);
int t1=op[0]-'a'+1,t2=op[2]-'a'+1,d=op[4]-'0';
mtx.e[t1][t2+26*(d-1)]=1;
mtx.e[t2][t1+26*(d-1)]=1;
vis[t1][t2]=1;
vis[t2][t1]=1;
}
for(int i=1;i<=26;i++)
for(int j=1;j<=26;j++)
if(!vis[i][j])mtx.e[i][j]=1;
for(int i=0;i<=26;i++)
mtx.e[0][i]=1;
int sum=0;
Matrix ans;
memset(ans.e,0,sizeof(ans.e));
pow(mtx,n,ans);
for(int i=0;i<=26;i++)
for(int j=1;j<=26;j++)
{
sum+=ans.e[i][j];
if(sum>=mod)sum-=mod;
}
printf("%d",sum);
}