AtCoder Beginner Contest 310G

G - Takahashi And Pass-The-Ball Game

Problem Statement

There are N N N Takahashi.

The i i i-th Takahashi has an integer A i A_i Ai and B i B_i Bi balls.

An integer x x x between 1 1 1 and K K K, inclusive, will be chosen uniformly at random, and they will repeat the following operation x x x times.

  • For every i i i, the i i i-th Takahashi gives all his balls to the A i A_i Ai-th Takahashi.

Beware that all N N N Takahashi simultaneously perform this operation.

For each i = 1 , 2 , … , N i=1,2,…,N i=1,2,,N, find the expected value, modulo 998244353 998244353 998244353, of the number of balls the i i i-th Takahashi has at the end of the operations.

How to find a expected value modulo 998244353 998244353 998244353

It can be proved that the sought probability is always a rational number. Additionally, the constraints of this problem guarantee that if the sought probability is represented as an irreducible fraction y x \frac{y}{x} xy, then x x x is not divisible by 998244353 998244353 998244353. Here, there is a unique 0 ≤ z < 998244353 0≤z<998244353 0z<998244353 such that y ≡ x z   ( mod  998244353 ) y≡xz~(\text{mod}~998244353) yxz (mod 998244353), so report this z z z.

题目大意:

N ( N ≤ 2 × 1 0 5 ) N(N\leq2\times10^5) N(N2×105) 个高橋( terrifying you know? \text{terrifying you know?} terrifying you know?)在玩传球游戏,第 i i i 个高橋初始时有 B i ( B i < 998244353 ) B_i(B_i<998244353) Bi(Bi<998244353) 个球,每次传球他会把自己手里的所有球传给第 A i A_i Ai 个高橋,高橋们同时传球不分先后,有一个随机数 x ∈ [ 1 , K ] ,   ( K < 1 0 18 ) x\in[1,K],~(K<10^{18}) x[1,K], (K<1018) 为他们将要进行的传球轮数,问每个高橋在这么多次传球之后手中的球数的数学期望[1],将其模上一个大质数 998244353 998244353 998244353 [2]。

[1]数学期望(mathematic expectation)(或均值,亦简称期望,平均数/均值和标准差是描述数据资料集中趋势和离散程度的两个最重要的测度值),此处数学期望即为每次传球每个高橋持有的球数之平均数
[2]分数取模,即求逆元,数据保证分母不为大质数之倍数,可以使用费马小定理 a p − 1 ≡ 1   ( mod  p ) a^{p-1}≡1~(\text{mod}~p) ap11 (mod p) ,其中 p p p 为质数, a a a 不为 p p p 的倍数,变形可得 a p − 2 ≡ a − 1   ( mod  p ) a^{p-2}≡a^{-1}~(\text{mod}~p) ap2a1 (mod p) ,所以有 b / a = b ⋅ a − 1 ≡ b ⋅ a p − 2   ( mod  p ) b/a=b\cdot a^{-1}≡b\cdot a^{p-2}~(\text{mod}~p) b/a=ba1bap2 (mod p) ,自行对照题目中给的求法理解。

分析:

我真的尽力了(),真的讲不清楚()。

K K K 的数据范围易见此题使用倍增或二分(其实本质都一样的哈),如果将 N N N 个高橋的传球关系想象成图,那么这个图就是一个有着 N N N 个节点 N N N 条有向边构成的图(保证每个节点都有且仅有一条出边,不保证联通),由此可以发现每一个联通的部分都是一个有着 x x x 个顶点 x x x 条边的有向图(保证每个节点都有且仅有一条出边),所以该部分为一个内向基环树,内向基环树有一个特点就是可以倍增。

我们考虑每个高橋可以接到哪些球

如题解中的图:img

我们可以发现,他们是可以合并的:令 T a k a i , j Taka_{i,j} Takai,j 为图中左部上数第 i i i 排左数第 j j j 个高橋, T a k a 1 , 1 Taka_{1,1} Taka1,1 把球传给 T a k a 2 , 3 Taka_{2,3} Taka2,3 T a k a 2 , 1 Taka_{2,1} Taka2,1 将球传给 T a k a 4 , 3 Taka_{4,3} Taka4,3 ,易得由相同列数的高橋传球给列数相同的新高橋,即若 T a k a i , 1 Taka_{i,1} Takai,1 将球传给 T a k a i + 1 , x Taka_{i+1,x} Takai+1,x ,则 T a k a j , 1 Taka_{j,1} Takaj,1 将球传给 T a k a j + 1 , x Taka_{j+1,x} Takaj+1,x ,所以可以合并。对于每一排高橋,下面都有有向线段指向新高橋,我们称之为对应关系,那么每两排对应关系可以生成新一排的对应关系;合并时将每两排有着对应关系或对应位置的高橋累加。
如果两组对应关系分别为 A [   ] A[~] A[ ] a [   ] a[~] a[ ] ,数值分别为 B [   ] B[~] B[ ] b [   ] b[~] b[ ] (前者累向后者),那么合并后新的对应关系分别为 A [ a [ i ] ] A[a[i]] A[a[i]] ,累加关系为 b [ i ] + = B [ i ] , b [ A [ i ] ] + = B [ i ] b[i]+=B[i],b[A[i]]+=B[i] b[i]+=B[i],b[A[i]]+=B[i]

由此,我们可以得到一个有着可以接受的时间复杂度的算法,时间复杂度为 O ( N ⋅ log ⁡ K + log ⁡ m o d ) O(N\cdot\log K+\log mod) O(NlogK+logmod) ,其中 log ⁡ K \log K logK 最大约为 60 60 60 ,能过,代码如下:
tips:注意 K K K传球次数而非高橋排数,上图左部中的 K K K 3 3 3 而非 4 4 4 ,并且最终结果并不算上初始一排高橋,所以实际操作中需要注意加减。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define md 998244353
#define MAXN 200010
int n;
ll k,a[MAXN],b[MAXN],Ta[MAXN],Tb[MAXN],pa[MAXN],pb[MAXN];//此处并非所有数组都需要开到ll,需要的为所有涉及乘法除法的
ll power(ll a,ll b){//快速幂
	if(a==0) return 0;
	if(a==1||b==0) return 1;
	if(b%2==0){
		ll x=power(a,b/2);
		return x*x%md;
	}else
		return power(a,b-1)*a%md;
}void perform(ll Ta[],ll Tb[],ll a[],ll b[]){//将ab累到TaTb上,最后的解在TaTb中
	for(int i=1;i<=n;++i)
		pa[i]=Ta[a[i]],pb[i]=0;//papb为临时数组,其内数值即为新一排的高橋,此处处理新对应关系的同时别忘了给pb清零
	for(int i=1;i<=n;++i)
		(pb[i]+=Tb[i])%=md,(pb[Ta[i]]+=b[i])%=md;//由对应关系和对应位置累加
	for(int i=1;i<=n;++i)
		Ta[i]=pa[i],Tb[i]=pb[i];//将值赋到TaTb数组中
	return;
}void dfs(ll k){//此处采用尾部指针二分递归求解
	if(k==1)
		return;//只有一排高橋不需累加
	dfs(k/2);
	perform(Ta,Tb,Ta,Tb);//dfs结束回到这里的时候,TaTb是k/2排高橋累加后的结果,所以累上一个自身
	if(k%2)//如果k为奇数,还需累上一排初始高橋
		perform(Ta,Tb,a,b);
	return;
}
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;++i)
		cin>>a[i],Ta[i]=a[i];//初始化
	for(int i=1;i<=n;++i)
		cin>>b[i],Tb[i]=b[i];//这里根据上面所写的递归是必要的,因为在k=2时需要累加自身
	dfs(++k);--k;//注意加减
	for(int i=1;i<=n;++i)
		(Tb[i]+=md-b[i])%=md;//减去初始高橋
	k%=md;ll inv=power(k,md-2);//k次操作,inv即为k的逆元
	for(int i=1;i<=n;++i)
		cout<<(Tb[i]*inv)%md<<" ";//对每一个高橋的总球数乘上k的逆元
	cout<<endl;
	return 0;
}
我们考虑每个高橋可以把球传给哪些人

对于一个内向基环树,我们容易得到一个结论,它由一棵树添上一条边构成,也便是由一个环和环外的一些指向环的边和点构成。由这个性质可得,每个节点走一定的步数之后都会陷入这个环中,所以我们可以由此得到每个高橋把自己的球都传给了哪些人。程序没写(),估计不是很好写。

另外题解中有着 O ( N + log ⁡ m o d ) O(N+\log mod) O(N+logmod) 时间复杂度的算法大概就是这么做的,附有数学证明。
https://atcoder.jp/contests/abc310/editorial/6800
https://atcoder.jp/contests/abc310/editorial/6799

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值