老板的题qaq
题目描述
n 个星球,有 m 条星球与星球之间的双向航道。(莫得航道的两个星球不可互相到达)
可以进行如下操作:
生成 Ti 个生物到一个星球 Xi,并给定这些生物的智商程度 Yi
破坏一条航道,航道编号为 Si
询问给定的一个星球 Xi ,从 Xi 出发可以到达的所有星球中选择 Ni 个生物,使得他们的智商程度都为 Yi的概率为多少,对 19260817 数取模。
输入数据不保证没有重边和自环,不保证同一条边不会被切断两次以上。
输入格式
第一行三个正整数 n,m,q
接下来 n 行,每行两个正整数 Ti , Yi ,分别代表第 ii 个星球初始生物数和智商程度
接下来 m 行,每行两个正整数 Xi , Yi ,分别代表这条道路的起点和终点
接下来 q 行,每行第一个正整数 opt(1≤opt≤3)
当 opt=1 时,表示添加生物,输入三个整数 Xi , Ti , Yi
当 opt=2时,表示删除航道,输入一个整数 Xi
当 opt=3 时,表示询问,输入三个整数 Xi , Ni , Yi
输出格式
对于每一个 opt=3 的操作,输出一行一个整数。
说明/提示
对于 30% 的数据,1≤n,m,q≤100
对于 60% 的数据, 1≤n,m,q≤50000
对于 100% 的数据,1≤n,m,q≤400000
对于 100% 的数据,保证所有生物的智商 ≤N
对于 100% 的数据,保证每次添加的人数和初始人数都不超过10
对于 100% 的数据,保证数据随机生成
这题思路的话大概20多分钟…
1.求概率
比如选3个,可选的有9个,一共有20个,结果就是9/20 * 8/19 * 7/18,
化简一下就是(9!/6!)/(20!/17!)
所以...预处理一下阶乘,取模用费马小定理求逆元即可
*注意:fac[0] = 1
毕竟可能有除0的情况...或者说,取0的时候没办法求逆元。
2.维护修改
无向图,连通就行,那就并查集qwq?
因为只有删边没有加边,可以离线…
先把所有没删的边连上(注意要忽略删除两次的),增加生物的操作都加上
然后倒序枚举的时候,加生物→减生物,删边→加边(并查集合并)
最后再正序输出答案就行了
3.维护生物个数
不会用map...直接数组(w[i][j]:i星球j生物个数)就TLE+MLE
复杂度...O(能过) (毕竟数据全随机嘛qaq)
void merge(int x,int y) { x = getfa(x),y = getfa(y); if(x == y) return; if(w[x].size() > w[y].size()) swap(x,y); fa[x] = y; for(map<int,int>::iterator i = w[x].begin(); i != w[x].end(); i++) w[y][(*i).first] += (*i).second; sum[y] += sum[x]; }
map写起来和数组差不多,for循环改一下就行了。还方便启发式合并(.size())!
遍历的时候用迭代器(注意迭代器不能写 <=.end(),只能写 !=.end() )
然后比如 m[a] = x,i是迭代器,(*i).first就是a,(*i).second就是x
也就是m[(*i).first] = (*i).second
debug:
1.n和q写反了...
2.f[0] = 1
代码如下
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<map> #define MogeKo qwq #define Darcy amour using namespace std; const int maxn = 4e5+10; const int mod = 19260817; int n,m,q,x,y; int fa[maxn],op[maxn]; long long a[maxn],b[maxn],t[maxn],ans[maxn]; long long sum[maxn],f[maxn*10+10]; bool del[maxn]; map <int,int> w[maxn]; struct edge { int l,r; } e[maxn]; int getfa(int x) { if(fa[x] == x) return x; return fa[x] = getfa(fa[x]); } void init() { for(int i = 1; i <= n; i++) fa[i] = i; } void merge(int x,int y) { if(x == y) return; x = getfa(x); y = getfa(y); if(x == y) return; if(w[x].size() > w[y].size()) swap(x,y); fa[x] = y; for(map<int,int>::iterator i = w[x].begin(); i != w[x].end(); i++) w[y][(*i).first] += (*i).second; sum[y] += sum[x]; } void getfac() { f[0] = 1; f[1] = 1; for(int i = 2; i <= maxn*10; i++) f[i] = ((long long)(f[i-1]%mod)*(i%mod))%mod; } long long qpow(int a,int b) { long long ans = 1,base = a; while(b) { if(b&1) (ans *= base) %= mod; (base *= base) %= mod; b >>= 1; } return ans%mod; } long long inv(int x) { return qpow(x,mod-2)%mod; } int calc(int x,int y,int k) { if(w[x][y] < k) return 0; long long p = f[w[x][y]] * inv(f[w[x][y]-k]) % mod; long long q = f[sum[x]] * inv(f[sum[x]-k]) % mod; return p*inv(q)%mod; } int main() { scanf("%d%d%d",&n,&m,&q); init(); getfac(); for(int i = 1; i <= n; i++) { scanf("%d%d",&x,&y); w[i][y] += x; sum[i] += x; } for(int i = 1; i <= m; i++) scanf("%d%d",&e[i].l,&e[i].r); for(int i = 1; i <= q; i++) { scanf("%d%lld",&op[i],&a[i]); if(op[i] == 1) { scanf("%lld%lld",&t[i],&b[i]); w[a[i]][b[i]] += t[i]; sum[a[i]] += t[i]; } if(op[i] == 2) { if(!del[a[i]]) del[a[i]] = true; else op[i] = 0; } if(op[i] == 3) scanf("%lld%lld",&t[i],&b[i]); } for(int i = 1; i <= m; i++) if(!del[i]) merge(e[i].l,e[i].r); for(int i = q; i >= 1; i--) { if(op[i] == 1) { x = getfa(a[i]); w[x][b[i]] -= t[i]; sum[x] -= t[i]; } if(op[i] == 2) merge(e[a[i]].l,e[a[i]].r); if(op[i] == 3) { x = getfa(a[i]); ans[i] = calc(x,b[i],t[i]); } } for(int i = 1; i <= q; i++) if(op[i] == 3) printf("%lld ",ans[i]); return 0; }