刷题集--杰杰的女性朋友

题意:杰杰是魔法界的一名传奇人物。他对魔法具有深刻的洞察力,惊人的领悟力,以及令人叹为观止的创造力。自从他从事魔法竞赛以来,短短几年时间,就已经成为世界公认的实力最强的魔法选手之一。更让人惊叹的是,他几乎没有借助外界力量,完全凭借自己的努力达到了普通人难以企及的高度。在最近的世界魔法奥林匹克竞赛上,他使用高超的魔法本领,一路过关斩将,在最后时刻一举击败了前冠军“旅行者”,获得了魔法界最高的荣耀:女神奖杯!女神奖杯可不是一个普通的奖杯,她能够帮杰杰实现一个愿望。
杰杰本着实事求是的态度,审时度势,向女神奖杯提出了自己的愿望:想要一个女性朋友。

杰杰的愿望实现了,可是女性朋友却和他不在一个城市。杰杰想要知道:如果要到达女性朋友的所在城市,有多少种方案供他选择?
杰杰所在的世界有n个城市,从1到n进行编号。任意两个城市都通过有向道路连接。每个城市u有k个入点权:$in[1],in[2]...in[k],有k个出点权:ou[1],ou[2]...ou[k]。对于任意两个城市(u,v)(u可以等于v),u到v的道路条数为(ou[1] \times in[v][1]+ou[2] \times in[v][2]+...+ou[k] \times in[v][k])条。杰杰有m次询问,每次询问由三元组(u,v,d)构成,询问从u城市通过不超过d条道路到达v$城市的方案数。
为了温柔的杰杰和他的女性朋友的美好未来,帮助他解答这个问题吧。

发现暴力矩阵快速幂一次就要n^3,但发现这个矩阵是由n*k和k*n两个矩阵相乘所得,更换中间乘的顺序快速幂里就变成k*k的矩阵,再乘上刚开始的n*k,最后一次不要全乘,就算要知道答案的那位即可。而因为要知道的是小于等于d步,新建一个点接受从v点来的答案及上一次答案即可。

#pragma GCC optimize(3,"inline","Ofast")
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=65,K=25;
const int mod=1e9+7;
int n,k,m,ot[N][K],in[K][N],tp[N][K];
struct Mat{
    int a[K][K];
    void init0()
    {memset(a,0,sizeof a);}
    void init1()
    {
        memset(a,0,sizeof a);
        for(int i=1;i<=k;i++)a[i][i]=1;
    }
};
Mat operator *(const Mat x,const Mat y)
{
    Mat res;res.init0();
    for(int i=1;i<=k;i++)
    for(int j=1;j<=k;j++)
    for(int kk=1;kk<=k;kk++)
    res.a[i][j]=(1LL*x.a[i][kk]*y.a[kk][j]%mod+res.a[i][j])%mod;
    return res;
}
Mat qpow(Mat x,int y)
{
    Mat res;res.init1();
    while(y)
    {
        if(y&1)res=res*x;
        x=x*x;y>>=1;
    }
    return res;
}
int main()
{
    Mat nw;int ans,u,v,d;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=k;j++)
            scanf("%d",&ot[i][j]);
        for(int j=1;j<=k;j++)
            scanf("%d",&in[j][i]); 
    }
    ++k,++n;
    scanf("%d",&m);
    while(m--)
    {
        memset(tp,0,sizeof tp),ans=0;
        scanf("%d%d%d",&u,&v,&d);
        for(int i=1;i<=n;i++)ot[i][k]=(i==v||i==n)?1:0;
        in[k][n]=1;nw.init0();
        for(int i=1;i<=k;i++)
            for(int j=1;j<=k;j++)
                for(int kk=1;kk<=n;kk++)
                    nw.a[i][j]=(1LL*in[i][kk]*ot[kk][j]%mod+nw.a[i][j])%mod;
        nw=qpow(nw,d);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=k;j++)
                for(int kk=1;kk<=k;kk++)
                    tp[i][j]=(1LL*ot[i][kk]*nw.a[kk][j]%mod+tp[i][j])%mod;
        for(int kk=1;kk<=k;kk++)
            ans=(1LL*tp[u][kk]*in[kk][n]+ans)%mod;
        printf("%lld\n",ans);      
    }
}

猜你喜欢

转载自blog.csdn.net/caoyang1123/article/details/82685915