[航海协会]给国与赌场
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[航海协会]给国与赌场相关的知识,希望对你有一定的参考价值。
给国与赌场
题目概述
题解
首先我们看第
2
2
2个子任务,容易发现,每次一定是会将现在所有钱都扔进去,然后赢
n
n
n把得到结果。
也就是说,如果我们每次只扔一部分的话,一定是不优的。
形象一点理解的话,如果我们每次都只扔一部分的话,假设我们扔了很多次,由于赢的概率是小于
1
2
\\frac12
21的,所以我们进行无数次后,它一定是一个重心在下方的概率分布,大概是这样,随便拿喷枪画的图
可以发现,我们跳得越多,是期望越向下的,所以在
a
=
1
,
b
=
2
n
a=1,b=2^n
a=1,b=2n的情形下,每次都全力往上跳肯定是更优的。
当然,如果你非要让我严谨证明的话,我就只能选择放弃了。
但任意时候都一定是全力往上跳更加优秀吗?并不是的。
事实上,我们观察到,每次我们会使用的值其实是该数的最小的二进制位。
形象点理解,如果我们现在用较高位跳的话,那么之后显然就用不了最低位了,最后加满的时候一定会多出来一位,这不就浪费了吗?
所以我们每次一定都只会加上最低位,事实上,也不太会几位一起加,这也会造成浪费。
于是,我们就能很快的规划出来一个
d
p
dp
dp转移式子,定义
d
p
i
,
0
/
1
dp_i,0/1
dpi,0/1表示现在的正枚举到原数的第
i
i
i位,并且有没有进位。
定义
g
(
i
)
g(i)
g(i)表示原数在
1
2
i
\\frac12^i
2i1这里有没有值。可以得到
f
i
,
0
=
[
g
(
i
+
1
)
]
p
f
i
+
1
,
0
+
[
¬
g
(
i
+
1
)
]
(
f
i
+
1
,
0
+
(
1
−
p
)
f
i
+
1
,
1
)
f
i
,
1
=
[
g
(
i
+
1
)
]
(
f
i
+
1
,
1
+
(
1
−
p
)
f
i
+
1
,
0
)
+
[
¬
g
(
i
+
1
)
]
p
f
i
+
1
,
1
f_i,0=[g(i+1)]pf_i+1,0+[\\neg g(i+1)](f_i+1,0+(1-p)f_i+1,1)\\\\ f_i,1=[g(i+1)](f_i+1,1+(1-p)f_i+1,0)+[\\neg g(i+1)]pf_i+1,1
fi,0=[g(i+1)]pfi+1,0+[¬g(i+1)](fi+1,0+(1−p)fi+1,1)fi,1=[g(i+1)](fi+1,1+(1−p)fi+1,0)+[¬g(i+1)]pfi+1,1这样,对于
b
=
2
n
b=2^n
b=2n的情况,我们就能够
O
(
T
n
)
O\\left(Tn\\right)
O(Tn)地
d
p
dp
dp转移求解了。
接下来,让我们想想,如果我们的分母不是
2
2
2的幂该怎么办。
事实上,即使分母不是
2
2
2的幂的话,即使转化成二进制下的小数,也是可以表示成一个循环小数的。
容易发现,非循环部分与循环部分的长度都是不会超过
b
b
b的,因为它在每一位的时候都相当于对于一个
x
b
\\fracxb
bx的形式,检查分子是否大于分母的一半,从而对这一位赋予
0
/
1
0/1
0/1,而
x
x
x也是不会超过
b
b
b的,当然最多只有
b
b
b种。
那么我们对于这样的循环小数该怎么
d
p
dp
dp,乘很多次让它趋近于答案?这是带模的耶。
没事,带模也是可以收敛的嘛。
我们每次的变化不是一个线性变化嘛,所以我们相当于先乘上一些矩阵,再循环乘一些矩阵。
每个循环节显然是可以表示成一个矩阵的,我们乘的是这个矩阵的无穷次方,相当于它收敛后的矩阵。
但我们该怎么求这个矩阵幂的收敛呢?可以注意到这个矩阵实际上是一个马尔科夫矩阵,每一列的和都为
1
1
1,它的收敛我们可以通过特征向量求出。
准确说,就是将特征值为
1
1
1的向量求出来,每列放一个,就是我们收敛后的结果了。
证明网上有很多,这里就不解释了。说实话这篇题解好像什么都没证。
通过计算得到,我们原矩阵
[
p
q
1
−
p
1
−
q
]
\\left[\\beginarraycp&q\\\\1-p&1-q\\endarray\\right ]
[p1−pq1−q]对应的收敛矩阵为
[
1
−
p
1
−
p
+
q
1
−
p
1
−
p
+
q
q
1
−
p
+
q
q
1
−
p
+
q
]
\\left[\\beginarrayc\\frac1-p1-p+q & \\frac1-p1-p+q\\\\\\fracq1-p+q&\\fracq1-p+q\\endarray\\right]
[1−p+q1−p1−p+qq1−p+q1−p1−p+qq]。
我们把循环节的收敛矩阵求出来,乘在非循环的部分矩阵之积上即可。
时间复杂度 O ( T b ) O\\left(Tb\\right) O(Tb)。
源码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define MAXN 1000005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lowbit(x) (x&-x)
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const double Pi=acos(-1.0);
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
x*=f;
int gcd(int a,int b)return b?gcd(b,a%b):a;
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;return t;
int T,a,b,p,q,totd,val[MAXN],d[MAXN];bool vis[MAXN];
struct matrix
int c[2][2];matrix()
void clear()
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)c[i][j]=0;
matrix operator * (const matrix &rhs)const
matrix res;res.clear();
for(int i=0;i<2;i++)
for(int k=0;k<2;k++)if(c[i][k])
for(int j=0;j<2;j++)
Add(res.c[i][j],1ll*c[i][k]*rhs.c[k][j]%mo,mo);
return res;
void print()
for(int i=0;i<2;i++,[航海协会]基因切割