ssoj2469叶落归根(矩阵乘法)

【题意】 你要做的是对于每一个起始点 s 以及每一个总时长 t(1<=t<=Q 且为整数 ) 求出落叶在起始点为 s 且经过 t 单位时间后的位置也是 s 的方案数。

两个方案不同,当且仅当两个方案中存在至少一个时刻落叶所经过的边不是图G中的同一条边。

为了便于检验,只需要输出所有情况(即所有不同的起始点和总时长,一共n*Q种情况)的方案数对给定正整数P取模后的异或和即可——也就是说,假设所有情况的方案数分别是ans1、ans2、ans3……你要输出的就是(ans1 mod P) xor (ans2 mod P) xor (ans3 mod P)……

【题解】实际上是矩阵乘法:设邻接矩阵为G,我们要知道的其实就是G^1~Q这Q个矩阵的一条对角线。
预处理出G^1~根号Q和G^根号Q到Q ,那么对于任意的 G^i,都可以变成2个已有矩阵的乘积,而我们只需要其一条对角线上共n个元素,所以这一步是O(n^2)的。

【代码】

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=106;
const ll inf=(ll)1<<61;
int n,t,mod,f[maxn][maxn][maxn]; 
int ans=0,g[maxn][maxn][maxn],h[maxn][maxn];
inline int get(){
    char c;while(!isdigit(c=getchar()));
    int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
    return v;
}
inline void cheng(int(*c)[maxn],int(*a)[maxn],int(*b)[maxn]){//矩阵乘法
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j){
            ll tmp=0;
            for(int k=1;k<=n;++k){
                tmp+=(ll)a[i][k]*b[k][j];
                if(tmp>=inf)tmp%=mod;
            }
            tmp%=mod;
            c[i][j]=tmp;
        }
}
inline void cal(int(*a)[maxn],int(*b)[maxn]){//两个矩阵合并来的路径长为t的矩阵
    for(int i=1;i<=n;++i){
        ll tmp=0;
        for(int j=1;j<=n;++j){
            tmp+=(ll)a[i][j]*b[j][i];
            if(tmp>=inf)tmp%=mod;
        }   
        tmp%=mod;
        ans^=tmp;
    }
}
int main(){
    n=get();t=get();mod=get();
    for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)h[i][j]=get();
    int sqr=(int)sqrt(t)+1;
    for(int i=1;i<=n;++i)f[0][i][i]=g[0][i][i]=1;
    for(int i=1;i<sqr;++i)cheng(f[i],f[i-1],h);
    cheng(g[1],f[sqr-1],h);
    for(int i=2;i<=sqr;++i)cheng(g[i],g[i-1],g[1]);
    for(int i=1;i<=t;++i){//共t个
        cal(g[i/sqr],f[i%sqr]);//两个待合并的矩阵,自己推一下
    }
    printf("%lld\n",ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值