P6841
Solution
有趣的题目 . 建议评分 : 紫 .
考虑把每个字母看做一个点 , 距离看做边 , 那么就相当于在有向图上找长度不超过
好像比较难 , 先来看几个简单问题 .
问题 1
给你一个图 , 节点数
我会 DP !
根据经验 , 如果一个 DP 朴素写法只改变一个维度 , 这个维度只与上一个有关系 , 那么可以矩阵加速 .
尝试构造转移矩阵 , 把第
初始矩阵应为单位矩阵 (
问题 2
给你一个图 , 节点数
和上一个问题很相似 , 可惜上一个算法不再使用 . 考虑拆点 , 给每一个点
如果
然后回归本题 . 用问题 2 中的算法可以解决长度为
我们可以创建一个虚点 , 向自己和其它字母的主点连边 , 这样找从虚点到主点长度为
练习题 :
P4159 [SCOI2009] 迷路
P2886 [USACO07NOV] Cow Relays G
P3758 [TJOI2017] 可乐
code :
#include<bits/stdc++.h>
#define int long long
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=200+10,MOD=1e9+7;
struct Matrix {
int n,m,val[MAXN][MAXN];
void init(int N,int M) {
return n=N,m=M,memset(val,0,sizeof(val)),void();
}
void output(void) {
printf("Matrix Output:\n%lld %lld\n",n,m);
ffor(i,1,n) {
ffor(j,1,m) printf("%lld ",val[i][j]);
printf("\n");
}
return ;
}
};
Matrix unit_matrix(int n) {
Matrix res;
res.init(n,n);
ffor(i,1,n) res.val[i][i]=1;
return res;
}
Matrix operator *(Matrix A,Matrix B) {
Matrix res;
int p=A.n,q=A.m,r=B.m;
res.init(p,r);
ffor(k,1,q) ffor(i,1,p) ffor(j,1,r) res.val[i][j]+=A.val[i][k]*B.val[k][j],res.val[i][j]%=MOD;
return res;
}
Matrix operator ^(Matrix A,int p) {
Matrix base=A,res=unit_matrix(A.n);
while(p) {
if(p&1) res=res*base;
base=base*base,p>>=1;
}
return res;
}
int n,m;
signed main() {
Matrix A;
A.init(5*26+1,5*26+1);
cin>>n>>m;
ffor(i,1,26) A.val[i][i+26]=A.val[i+26][i+26*2]=A.val[i+26*2][i+26*3]=A.val[i+26*3][i+26*4]=1;
ffor(i,1,26) ffor(j,1,26) A.val[i][j]=A.val[j][i]=1;
ffor(i,1,m) {
char ch1,ch2;int len;
cin>>ch1>>ch2>>len;
A.val[ch1-'a'+1][ch2-'a'+1]=A.val[ch2-'a'+1][ch1-'a'+1]=0;
A.val[ch1-'a'+1+26*(len-1)][ch2-'a'+1]=1,A.val[ch2-'a'+1+26*(len-1)][ch1-'a'+1]=1;
}
ffor(i,1,26) A.val[131][i]=1;
A.val[131][131]=1,A=A^(n+1);
int ans=0;
ffor(i,1,26) ans+=A.val[131][i],ans%=MOD;
cout<<ans;
return 0;
}