[CQOI2018] 社交网络

Description

当今社会,在社交网络上看朋友的消息已经成为许多人生活的一部分。通常,一个用户在社交网络上发布一条消息
(例如微博、状态、Tweet等)后,他的好友们也可以看见这条消息,并可能转发。转发的消息还可以继续被人转
发,进而扩散到整个社交网络中。在一个实验性的小规模社交网络中我们发现,有时一条热门消息最终会被所有人
转发。为了研究这一现象发生的过程,我们希望计算一条消息所有可能的转发途径有多少种。为了编程方便,我们
将初始消息发送者编号为1,其他用户编号依次递增。该社交网络上的所有好友关系是已知的,也就是说对于A、B
两个用户,我们知道A用户可以看到B用户发送的消息。注意可能存在单向的好友关系,即A能看到B的消息,但B不
能看到A的消息。
还有一个假设是,如果某用户看到他的多个好友转发了同一条消息,他只会选择从其中一个转发,最多转发一次消
息。从不同好友的转发,被视为不同的情况。
如果用箭头表示好友关系,下图展示了某个社交网络中消息转发的所有可能情况。
初始消息是用户1发送的,加粗箭头表示一次消息转发

Input

输入文件第一行,为一个正整数n,表示社交网络中的用户数:
第二行为一个正整数m.表示社交网络中的好友关系数目。
接下来m行,每行为两个空格分隔的整数ai和bi,表示一组好友关系,即用户ai可以看到用户bi发送的消息。
1≤n≤250,1≤ai,bi≤n,1≤m≤n(n-1)

Output

输出文件共一行,为一条消息所有可能的转发途径的数量,除以1 0007所得的余数。

Sample Input

4
7
2 1
3 1
1 3
2 3
3 2
4 3
4 2

Sample Output

6

Solution

一眼矩阵树定理模板题,省选出这个真的。

用出度矩阵和临接矩阵相减构造基尔霍夫矩阵,求矩阵行列式。

Code

#include <iostream>
#include <cstdio>

#define R register
#define ll long long

using namespace std;

namespace Dntcry
{
	inline int read()
	{
		R int a = 0, b = 1; R char c = getchar();
		for(; c < '0'|| c > '9'; c = getchar()) (c == '-') ? b = -1 : 0;
		for(; c >= '0' && c <= '9'; c = getchar()) a = (a << 1) + (a << 3) + c - '0';
		return a * b;
	}
	const int Mod = 10007;
	int n, m, Map[310][310], inv[10010], Ans;
	int Guass()
	{
		R int res = 1;
		for(R int i = 2, j; i <= n; i++)
		{
			for(j = i; !Map[j][i]; j++) ;
			if(j > n) continue ;
			if(j != i) 
			{
				res = Mod - res;				
				for(R int k = i; k <= n; k++) swap(Map[i][k], Map[j][k]);
			}
			for(j = i + 1; j <= n; j++)
				if(Map[j][i])
				{
					R int tmp = Map[j][i] * inv[Map[i][i]] % Mod;
					for(R int k = i; k <= n; k++)
						Map[j][k] = (Map[j][k] - tmp * Map[i][k] % Mod + Mod) % Mod;
				}
		}
		for(R int i = 2; i <= n; i++) res = res * max(Map[i][i], 1) % Mod;
		return res;
	}
	int Main()
	{
		n = read(), m = read();
		inv[0] = inv[1] = 1;
		for(R int i = 2; i < 10010; i++) inv[i] = (Mod - Mod / i) * inv[Mod % i] % Mod;
		for(R int i = 1, u, v; i <= m; i++)
		{
			v = read(), u = read();
			Map[v][v] = (Map[v][v] + 1) % Mod;
			Map[u][v] = (Map[u][v] - 1) % Mod;
		}
		Ans = Guass();
		printf("%d\n", Ans);
		return 0;
	}
}
int main() { return Dntcry :: Main(); }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值