CF868G El Toll Caves

Link
最优的决策肯定是尽量均摊,不妨从前往后做,那么我们可以将(n,k)都除以(gcd(n,k))
(f_i)表示在第(i)个洞穴找到宝藏的期望天数,那么答案为(frac{sum f_i}n)
考虑(f_i)的转移式:

[f_i= egin{cases} f_{i-k}+1&iin[k,n)\ (1-p)f_i+1&iin[0,k) end{cases} ]

(A(f_i)=f_{i+k},B(f_i)=f_{i+k-n}),那么我们要求的就是(ans=sumlimits_{i=0}^{k-1}S1(f_i)+sumlimits_{i=k}^{n-1}S2(f_i))
考虑将((n,k))递归至((k,k'=nmod k))的子问题,此时(ans=sumlimits_{i=0}^{k'-1}S1'(f_i)+sumlimits_{i=k}^{n-1}S2'(f_i))
不难发现(S_1'=S1+sumlimits_{i=1}^{lfloorfrac nk floor}S2(A^i),S2'=S1+sumlimits_{i=1}^{lfloorfrac nk floor-1}S2(A^i))
注意到(f_{i+k-k'}=B(A^{lfloorfrac nk floor}(f_i))),因此(f_{i+k'-k}=A^{-lfloorfrac nk floor}(B^{-1}(f_i))),这就是(B')
同理可以推出(A')(f_{i+k'}=A^{-lfloorfrac nk floor-1}(B^{-1}(f_i)))

#include<cstdio>
#include<numeric>
using i64=long long;
const i64 P=1000000007,i2=P-P/2;
int read(){int x;scanf("%d",&x);return x;}
i64 pow(i64 a,i64 k){i64 r=1;for(;k;k>>=1,a=a*a%P)if(k&1)r=r*a%P;return r;}
i64 f(i64 x,i64 y){return y<=0? 0:x==1? y:pow(x-1,P-2)*(pow(x,y)-1)%P;}
i64 g(i64 x,i64 y){return y<=0? 0:x==1? y*(y+1)/2%P:pow(x-1,P-2)*((pow(x,y)-1)*pow(x-1,P-2)%P*x%P-y+P)%P;}
i64 solve(i64 n,i64 k,i64 a1,i64 a0,i64 b1,i64 b0,i64 s,i64 s1,i64 s2)
{
    if(n==1) return (s1*b0%P*pow(1-b1+P,P-2)+s)%P;
    i64 q=(n-1)/k,r=n-q*k,x,y,A1,A0,B1,B0,S,S1,S2;
    x=b1*pow(a1,q-1)%P,y=(a0*b1%P*f(a1,q-1)+b0)%P,A1=pow(x,P-2),A0=P-y*A1%P;
    x=b1*pow(a1,q)%P,y=(a0*b1%P*f(a1,q)+b0)%P,B1=pow(x,P-2),B0=P-y*B1%P;
    S=(s2*a0%P*(r*f(a1,q)%P+k*g(a1,q-1)%P)+s)%P,S1=(s2*a1%P*f(a1,q)+s1)%P,S2=(s2*a1%P*f(a1,q-1)+s1)%P;
    return solve(k,r,A1,A0,B1,B0,S,S1,S2);
}
void solve()
{
    i64 n,k,d;
    n=read(),k=read(),d=std::gcd(n,k),n/=d,k/=d;
    printf("%lld
",solve(n,k,1,1,i2,1,0,1,1)*pow(n,P-2)%P);
}
int main(){for(int t=read();t;--t) solve();}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12939308.html