CF868G El Toll Caves

5 篇文章 0 订阅
4 篇文章 0 订阅

题意:

n n n个洞穴,其中一个有宝藏。
你每天有 k k k次机会去洞穴中找宝藏,如果你去到的洞穴中有宝藏则有 1 2 \frac{1}{2} 21的概率找到。每次寻找的概率是独立计算的。
问找到宝藏的期望天数。

数据范围:

k ≤ n ≤ 5 ∗ 1 0 8 k \leq n \leq 5*10^8 kn5108

Analysis:

发现这 k k k次机会一定是有决策的,在随机意义下,我们选择尽量少的去找宝藏,那么就是 k k k k k k个选。在这样的情况下,无限找的话,每 g c d ( n , k ) gcd(n,k) gcd(n,k)个地方的期望找到的天数一样,我们可以将 n , k n,k n,k同时除 g c d gcd gcd答案不变。
f i f_i fi表示在第 i i i个洞穴找到宝藏的期望天数,那么答案就是 ∑ f i n \frac{\sum f_i}{n} nfi
我们发现对于前 n − k n-k nk个洞穴,会有 f i + k = f i + 1 f_{i+k}=f_i+1 fi+k=fi+1。因为每一次找 i i i前会先找 f i − k f_{i-k} fik
对于后 k k k个洞穴,会有 f i + k − n = ( 1 − p ) ∗ ( f i + 1 ) + p = ( 1 − p ) ∗ f i + 1 f_{i+k-n}=(1-p)*(f_i+1)+p=(1-p)*f_{i}+1 fi+kn=(1p)(fi+1)+p=(1p)fi+1。前一次没找到加上第一次就找到的概率。我们把这两种转移看做一种 A , B A,B A,B变换
我们考虑把答案如下表达:
a n s = ∑ i = 0 k − 1 S 1 ( f i ) + ∑ i = k n − 1 S 2 ( f i ) ans=\sum_{i=0}^{k-1}S1(f_i)+\sum_{i=k}^{n-1}S2(f_i) ans=i=0k1S1(fi)+i=kn1S2(fi)
以上的 A , B , S 1 , S 2 A,B,S1,S2 A,B,S1,S2都是形如 k x + b kx+b kx+b的一次函数形式的变换。
考虑对前 k k k个洞穴讨论,能够得到:
n n n% k = k ′ k=k' k=k
i i i [ k ′ , k ) [k',k) [k,k) f i + k ′ − k = B ′ = A − n k ( B − ( f i ) ) f_{i+k'-k}=B'=A^{-\frac{n}{k}}(B^-(f_i)) fi+kk=B=Akn(B(fi))。考虑第 i i i个转移多少次得到 f i + k ′ − k f_{i+k'-k} fi+kk,然后对于转移做逆变换。
同理,对于 i i i [ 0 , k ′ ) [0,k') [0,k),有 f i + k ′ = A ′ = A − n k − 1 ( B − ( f i ) ) f_{i+k'}=A'=A^{-\frac{n}{k}-1}(B^-(f_i)) fi+k=A=Akn1(B(fi))
我们把求 f i f_i fi的部分就转换成了求 n = k , k = k ′ n=k,k=k' n=k,k=k的子问题。 A ′ , B ′ A',B' A,B为新的 A , B A,B A,B
考虑求和部分也转换一下。
考虑把后面转移的 A A A全部加起来,可以得到:
S 1 = S 1 + ∑ i = 0 n k S 2 ( A i ) S1=S1+\sum_{i=0}^{\frac{n}{k}}S2(A^i) S1=S1+i=0knS2(Ai) S 2 = S 1 + ∑ i = 0 n k − 1 S 2 ( A i ) S2=S1+\sum_{i=0}^{\frac{n}{k}-1}S2(A^i) S2=S1+i=0kn1S2(Ai)
然后求复合函数的次幂部分,由于其满足结合律,我们可以快速幂。
那么这题就做完了,最后当 k = 0 k=0 k=0时,解个 x = k x + b x=kx+b x=kx+b的方程即可。
复杂度 O ( T log ⁡ n ) O(T\log n) O(Tlogn)

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
typedef long long ll;
const ll mo = 1e9 + 7;
const ll inv2 = mo - mo / 2;
struct node
{
	ll k,b;
	node operator * (node r) const
	{ return (node){k * r.k % mo,(b + k * r.b) % mo}; }
	node operator + (node r) const
	{ return (node){(k + r.k) % mo,(b + r.b) % mo}; }
};
int T;
ll n,k,p;
inline ll gcd(ll a,ll b) { return !b ? a : gcd(b,a % b); }
inline ll pow(ll x,ll p)
{
	ll ret = 1;
	for (; p ; p >>= 1,x = x * x % mo)
	if (p & 1) ret = ret * x % mo;
	return ret;
}
inline node C(node x,ll p)
{
	node ret = (node){1,0};
	for (; p ; p >>= 1,x = x * x)
	if (p & 1) ret = x * ret;
	return ret;
}
inline node G(node x,ll p)
{
	if (!p) return (node){0,0};
	if (x.k == 1) return (node){p,p * (p + 1) % mo * inv2 % mo * x.b % mo};
	node a = C(x,p + 1),z; a.k = (a.k - x.k + mo) % mo,a.b = (a.b - x.b + mo) % mo;
	z.k = a.k * pow(x.k + mo - 1,mo - 2) % mo;
	z.b = (z.k - p + mo) * pow(x.k + mo - 1,mo - 2) % mo * x.b % mo;
	return z;
}
inline ll solve(ll n,ll k,node A,node B,node s1,node s0)
{
	if (!k) return A.b * pow(mo + 1 - A.k,mo - 2) % mo * s0.k % mo;
	node ns1 = s1 + (s0 * G(A,n / k)),ns0 = s1 + (s0 * G(A,n / k - 1));
	node nA = B; ll ni = pow(nA.k,mo - 2); nA.k = ni,nA.b = (mo - nA.b * ni % mo) % mo;
	node nB = nA; ni = pow(A.k,mo - 2); A.k = ni,A.b = (mo - A.b * ni % mo) % mo;
	nA = C(A,n / k - 1) * nA,nB = C(A,n / k) * nB;
	ll S = ((n % k) * ns1.b % mo + (k - n % k) * ns0.b % mo) % mo; ns1.b = ns0.b = 0;
	return (solve(k,n % k,nA,nB,ns1,ns0) + S) % mo;
}
int main()
{
//	freopen("a.in","r",stdin);
	scanf("%d",&T);
	while (T--)
	{
		scanf("%lld%lld",&n,&k); p = inv2;
		ll d = gcd(n,k); n /= d,k /= d;
		printf("%lld\n",solve(n,k,(node){1,1},(node){mo + 1 - p,1},(node){1,0},(node){1,0}) * pow(n,mo - 2) % mo);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值