hdu 5607 bestcode 68

graph

Accepts: 30
Submissions: 188
Time Limit: 8000/4000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
在一个NNN个点(标号111~nnn),MMM条边的有向图上,一开始我在点uuu,每一步我会在当前点的出边中等概率的选一条走过去,求走了恰好KKK步后走到每个点的概率.
输入描述
第一行两个正整数N,MN,MN,M,表示点数和边数.
接下来MMM行,每行两个正整数X,YX,YX,Y.表示一条XXXYYY的一条有向边(保证没有重边和自环).
接下来一个正整数QQQ,表示询问个数.
接下来QQQ行,每行两个正整数u,Ku,Ku,K,表示开始的点和步数.
N≤50,M≤1000,Q≤20,u≤n,K≤109N \leq 50, M \leq 1000, Q \leq 20, u \leq n, K \leq 10^{9}N50,M1000,Q20,un,K109.
每个点保证至少有一个出边.
输出描述
QQQ行,每行NNN个数字,用空格隔开,第iii个数字表示从uuu开始走KKK步到iii的概率.
考虑到输出的答案可能会有精度问题,经过一定的分析后可以发现答案一定可以被表示成XY\frac{X}{Y}YX的形式,你只需输出X×Y109+5 mod (109+7)X \times Y^{10^9+5} \ mod \ (10^9+7)X×Y109+5 mod (109+7)的值即可.

在每行后面多输出一个空格,否则可能会使你PE.
输入样例
3 2
1 2
1 3
1
1 1
输出样例
0 500000004 500000004 
Hint
这是一个三个点,两条边的有向图,它们分别是(1−>2,1−>3)(1->2,1->3)(1>2,1>3).现在在1号点,走了一步后,有1/2的概率走到了2,有1/2的概率走到了3,本来应该输出 0 0.5 0.5
而根据上面所说的,应输出1∗2109+5 mod (109+7)=5000000041*2^{10^9+5} \ mod \ (10^9+7)=50000000412109+5 mod (109+7)=500000004.
ac 代码 在矩阵初始化时不是0,1 而是概率的x/y的形势,a【i】【j】x是从i第k步到达j的方案数,而y是走k步的总方案数。
这样矩阵的k次幂后a【i】【j】代表从i走k步到j的概率。
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
typedef long long LL;
const int N = 50;
const int M = 1e9+7;
int out[55];
struct Matri{
	Matri(){
		memset(a,0,sizeof(a));
	}
	LL a[N+5][N+5];
}bs,A ;
Matri operator *(Matri a,Matri b)
{
	int i,j,k;
	Matri tmp;
	for(i=1;i<=N;i++){
		for(j=1;j<=N;j++){
			tmp.a[i][j] = 0;
			for(k=1;k<=N;k++)
			{
				tmp.a[i][j] =(tmp.a[i][j] + 1LL*a.a[i][k] * b.a[k][j])%M;  // ?
			}
		}
	}
	return tmp;
}
Matri pw(Matri a, int k){    //a的k次幂 
	int i;
	Matri tmp;
	memset(tmp.a,0,sizeof(tmp.a));
	for(i=0;i<=N;i++)
	tmp.a[i][i] = 1;
	while(k){
		if(k%2){
			tmp = tmp*a;   // 前后顺序 
		}
		a = a * a;
		k/=2;
	}
	return tmp;
}

LL pw(LL a,int k){       //a的k次幂 
	int i;
	LL tmp = 1;
	while(k){
		if(k%2){
			tmp = (a * tmp)%M;   // 前后顺序 
		}
		a = (a * a)%M;
		k/=2;
	}
	return tmp;
}

Matri work(int k){
	int i,j;
	Matri tmp;
	tmp = pw(bs,k);
 	return tmp;
}
void prit(Matri t){
	int i,j;
	for(i=1;i<=3;i++){
		for(j=1;j<=3;j++){
			printf("%d ",t.a[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int i,j,k,n,m,q;
	int u,v;
	int st;
	LL now;
	//printf("%I64d\n",pw(2,M-2));
	scanf("%d%d",&n,&m);
	memset(bs.a,0,sizeof(bs.a));
	for(i=0;i<m;i++){
		scanf("%d%d",&u,&v);
		bs.a[u][v] = 1;
		out[u]++;
	}                 
	for(i=1;i<=n;i++){
		now = pw(out[i],M-2);
		for(j=1;j<=n;j++)
		bs.a[i][j] = (bs.a[i][j] * now )%M;
	}                              //!! no above 5 line just wrong
	scanf("%d",&q);
	while(q--){
		Matri ans;
		LL total  = 0;
		scanf("%d%d",&st,&k);
		ans = work(k); 
		for(i=1;i<=n;i++){
			printf("%I64d ",ans.a[st][i]);
		}
		puts("");
	}
	return 0;
}



问题是wrong代码:
唯一不同就是矩阵存的是方案数。
于是进行了矩阵的k次幂后,我在求i到j走k步的方案数a【i】【j】(题意中x),然后得到i走k步的总方案数a【i】【1】+。。。+a【i】【n】(题意中y),然后
X×Y109+5 mod (109+7)。有问题么??????????

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
typedef long long LL;
const int N = 50;
const int M = 1e9+7;
int out[55];
struct Matri{
    Matri(){
        memset(a,0,sizeof(a));
    }
    LL a[N+5][N+5];
}bs,A ;
Matri operator *(Matri a,Matri b)
{
    int i,j,k;
    Matri tmp;
    for(i=1;i<=N;i++){
        for(j=1;j<=N;j++){
            tmp.a[i][j] = 0;
            for(k=1;k<=N;k++)
            {
                tmp.a[i][j] =(tmp.a[i][j] + 1LL*a.a[i][k] * b.a[k][j])%M;  // ?
            }
        }
    }
    return tmp;
}
Matri pw(Matri a, int k){       //a的k次幂
    int i;
    Matri tmp;
    memset(tmp.a,0,sizeof(tmp.a));
    for(i=0;i<=N;i++)
    tmp.a[i][i] = 1;
    while(k){
        if(k%2){
            tmp = tmp*a;   // 前后顺序
        }
        a = a * a;
        k/=2;
    }
    return tmp;
}

LL pw(LL a,int k){       //a的k次幂
    int i;
    LL tmp = 1;
    while(k){
        if(k%2){
            tmp = (a * tmp)%M;   // 前后顺序
        }
        a = (a * a)%M;
        k/=2;
    }
    return tmp;
}

Matri work(int k){
    int i,j;
    Matri tmp;
    tmp = pw(bs,k);
     return tmp;
}
void prit(Matri t){
    int i,j;
    for(i=1;i<=3;i++){
        for(j=1;j<=3;j++){
            printf("%d ",t.a[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    int i,j,k,n,m,q;
    int u,v;
    int st;
    LL now;
    //printf("%I64d\n",pw(2,M-2));
    scanf("%d%d",&n,&m);
    memset(bs.a,0,sizeof(bs.a));
    for(i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        bs.a[u][v] = 1;
    //    out[u]++;
    }
    //prit(bs);
//    for(i=1;i<=n;i++){
//        now = pw(out[i],M-2);
//        for(j=1;j<=n;j++)
//        bs.a[i][j] = (bs.a[i][j] * now )%M;
//    }        
    //prit(bs);                                       //!! no above 5 line just wrong
    scanf("%d",&q);
    while(q--){
        Matri ans;
        LL total  = 0;
        scanf("%d%d",&st,&k);
        ans = work(k);
        for(i=1;i<=n;i++){
            //for(j=1;j<=n;j++)
            total = (total + ans.a[st][i])%M ;
        }
        total = pw(total,M-2);    
        for(i=1;i<=n;i++){
            printf("%I64d ",(1LL*ans.a[st][i] * total)%M );
        }
        printf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值