HDU 5607 graph

8 篇文章 0 订阅
题意:

给定一个有向图,询问从某个点出发,走 K 步到达其它各点的概率,表示为 x/y,要求 xy5+109mod(7+109) .
N50,M1000,Q20,uN,K109

思路:

首先考虑一个一个经典的问题,就是:询问从某个点出发,走 K 步到达其它各点的方案数?

这个问题可以转化为矩阵相乘,所以矩阵快速幂即可解决。但是对于原问题的话,要求

xy5+109mod(7+109)
.

因为 (x/y) mod P = xyP2 mod P (因为P=7+109 为一个素数,满足费马小定理),所以我们可以把初始的矩阵每个元素值乘上 yP2 ,这样也就得到了最终的答案。

for(int i = 1;i <= n;i ++) {
    LL now = pw(out[i], 5 + 1e9);
    for(int j = 1;j <= n;j ++) {
        G[i][j] = (G[i][j] * now) % mod;
    }
}
代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <string>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>  P;
const int N = 55, mod = 7 + 1e9;
LL G[N][N];
struct Matrix  
{  
    int n;  
    LL a[N][N];  
    Matrix() {  
        memset(a, 0, sizeof(a));// kidding me .  
    }  
    Matrix(int ax){  
        n = ax;  
        memset(a, 0, sizeof(a));  
    }  
} ans, A;  


Matrix operator * (Matrix a, Matrix b)  
{  
    Matrix tmpans;  
    tmpans.n = a.n;  
    for(int i = 1; i <= a.n; i ++){  
        for(int j = 1; j <= a.n; j ++){  
            for(int k = 1; k <= a.n; k ++)  
            tmpans.a[i][j] = (tmpans.a[i][j] + a.a[i][k] * b.a[k][j]) % mod;    
        }  
    }  
    return tmpans;  
}  

void power(int k)  
{  
    while(k){  
        if(k & 1) ans = ans * A;  
        A = A * A;  
        k = k >> 1;  
    }  
}
void init(int k)
{
    memcpy(A.a, G, sizeof(A.a));  
    memset(ans.a, 0, sizeof(ans.a));
    for(int i = 1;i <= A.n;i ++) {
        ans.a[i][i] = 1;
    }
    power(k);
}
LL pw(LL a, int k)
{
    LL t = 1LL;
    while(k) {
        if(k & 1) t = (t * a) % mod;
        a = (a * a) % mod;
        k >>= 1;
    }
    return t;
}
int out[N];
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    A.n = n; ans.n = n;
    memset(G, 0, sizeof(G));
    memset(out, 0, sizeof(out));
    while(m --) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u][v] ++, out[u] ++;
    }
    for(int i = 1;i <= n;i ++) {
        LL now = pw(out[i], 5 + 1e9);
        for(int j = 1;j <= n;j ++) {
            G[i][j] = (G[i][j] * now) % mod;
        }
    }
    int Q;
    scanf("%d",&Q);
    while(Q --) {
        int u, k;
        scanf("%d%d", &u, &k);
        init(k);
        for(int i = 1;i <= n;i ++) {
            printf("%lld ", ans.a[u][i]);
        }
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值