HDU 5318 The Goddess Of The Moon (矩阵快速幂)

题目链接:HDU 5318 The Goddess Of The Moon

题意:给出N串字符串,若是一个字符串的后缀与另一个字符串的前缀相同并且长度大于1,就表示这两个字符串是可以相连的,问M个字符串相连不同方案数为多少。

思路:

1.将输入的字符串预处理存入一个矩阵中,mp[i][j]=1说明str[i]与str[j]能相连,反之,则不能相连。

2.str[i]与str[j]能相连 转化为 i点到j点可达,那么就可以得到一个有向图,长度为M的意思就是 两点之间所走的步数为M的不同走法有多少种——矩阵快速幂的经典问题


注意:

1.因为求不同的方案数,所以输入是要先去重


AC代码:

#include <stdio.h>
#include <string.h>
#include <string>
#include <map>
#include <iostream>
#define LL __int64
using namespace std;
const int kmod=1000000007;
string str[55],ss;
map<string,int> mp;
int N;
struct Matrix {
    LL m[55][55];
};
Matrix init;

Matrix MatrixMul(Matrix a, Matrix b){
    Matrix c;
    int i,j,k;
    for(i=0;i<N;i++){
        for(j=0;j<N;j++){
            c.m[i][j]=0;
            for(k=0;k<N;k++){
                c.m[i][j]+=(a.m[i][k]*b.m[k][j]);
                c.m[i][j]%=kmod;
            }
        }
    }
    return c;
}

Matrix QuickPow(Matrix m,int p){
    Matrix b;
    int i;
    memset(b.m,0,sizeof b.m);
    for(i=0;i<N;i++)
        b.m[i][i]=1;
    while(p){
        if(p%2) b=MatrixMul(b,m);
        p/=2;
        m=MatrixMul(m,m);
    }
    return b;
}

int gao(string a, string b) {
    int i,la,lb,j;
    la=a.length();
    lb=b.length();
    string ta,tb;
    for(i=0; i<la; i++) {
        ta=a.substr(i);
        //cout<<ta<<"---"<<endl;
        for(j=0; j<=lb; j++) {
            tb=b.substr(0,j);
            //cout<<tb<<"..."<<endl;
            if(ta==tb && (int)ta.length()>1) return 1;
        }
    }
    return 0;
}


void solve(int n) {
    int i,j;
    memset(init.m,0,sizeof init.m);
    for(i=0; i<n; i++) {
        for(j=0; j<n; j++) {
            if(i==j && (int)str[i].length()>1) init.m[i][j]=1;
            else init.m[i][j]=gao(str[i],str[j]);
        }
    }
}

/*

*/

int main() {
    //printf("%d\n",gao("1212","12"));
    int i,k,n,m;
    int t,cnt,j;
    scanf("%d",&t);
    while(t--) {
        mp.clear();
        cnt=0,k=0;
        scanf("%d %d",&n,&m);
        for(i=0; i<n; i++) {
            cin>>ss;
            if(mp.find(ss)==mp.end()) {
                mp[ss]=k++;
                str[cnt++]=ss;
            }
        }
        N=cnt;
        solve(n);
		
		if(m==0) {
			printf("0\n");
			continue;
		}
        Matrix ans;
        ans=QuickPow(init,m-1);
        LL sum=0;
        for(i=0;i<N;i++){
            for(j=0;j<N;j++){
               // printf("%I64d ",ans.m[i][j]);
                sum+=ans.m[i][j];
                sum%=kmod;
            }
            //printf("\n");
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

/*
131
3 4
121 123 213

131
3 3
121 123 213

2
3 10
12 1213 1212
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值