I. Improve SPAM |
---|
题意: 给你一个有向图,N个点中有1-L个为发送点,剩下的为接收点。点1发送一封邮件给他相邻的点,其他的点接着发送,可能会收到多封邮件,每封发送。问接收点一共接收到了多少封邮件,以及多少个接收点收到了邮件。
题解: 换个说法就是说,除了前L个点为发送点其余均为接受点,问从点1出发能够达到多少个接受点并且一共有多少条路径。
比赛时Sstee1XD直接用了BFS,中间加了一些优化,的确是最出来了。但是后续补题,我还是再写了一遍,加了一个拓扑排序的模板,跑的更快了。
思路: 因为不是所有的接受点都与1点连通,所以直接套拓扑排序是不可行的。需要从一点出发跑一遍BFS,将能够到达的点度数加一(拓扑需要)。结束之后只要一个标准的拓扑模板就能做。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
inline int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int N = 2e3 + 10;
const int mod = 1e9 + 7;
int n, m, deg[N];
set<int> S;
vector<int> V[N];
void topu(){
ll ans = 0;
ll num[N] = {0, 1};
queue<int> Q; Q.push(1);
while(!Q.empty()){
int u = Q.front(); Q.pop();
if(u > m){
ans += num[u];
if(ans >= mod) ans -= mod;
S.insert(u);
}
for(auto v : V[u]){
deg[v]--;
num[v] += num[u];
if(num[v] >= mod) num[v] -= mod;
if(!deg[v]) Q.push(v);
}
}
printf("%lld %d", ans, S.size());
}
void BFS(){
queue<int> Q; Q.push(1);
int vis[N] = {0, 1};
while(!Q.empty()){
int u = Q.front(); Q.pop();
for(auto v : V[u]){
deg[v]++;
if(!vis[v]) Q.push(v);
vis[v] = 1;
}
}
}
int main(){
n = read(), m = read();
for(int i = 1; i <= m; i++){
int t = read();
for(int j = 1; j <= t; j++){
int v = read();
V[i].push_back(v);
}
}
BFS();
topu();
return 0;
}