[航海协会]给国与赌场

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+(1p)fi+1,1)fi,1=[g(i+1)](fi+1,1+(1p)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 ] [p1pq1q]对应的收敛矩阵为 [ 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] [1p+q1p1p+qq1p+q1p1p+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++,[航海协会]基因切割

[航海协会]万灵药

[航海协会]SSSP

[航海协会]稀疏阶乘问题

[航海协会]身体

[航海协会]身体