锻造 (forging)

文章目录

题目

Description题目背景
题目描述

Input
第一行两个整数 n n n a a a,含义如题所示。
为了避免输入量过大,第二行五个整数 b x bx bx b y by by c x cx cx c y cy cy p p p,按照下列代码来生成 b b b c c c数组。

b[0]=by+1;c[0]=cy+1;
for(int i=1;i<n;i++){
	b[i]=((long long)b[i-1]*bx+by)%p+1;
	c[i]=((long long)c[i-1]*cx+cy)%p+1;
}

Output
输出一行一个整数,表示期望花费。

Sample Input1
0 6432
4602677 3944535 2618884 6368297 9477531

Sample Input2
1 3639650
6136976 5520115 2835750 9072363 9302097

Sample Input3
10 2
2 33 6 66 2333333

Sample Input4
200 5708788
0 0 0 0 1

Sample Output1
6432

Sample Output2
150643649

Sample Output3
976750710

Sample Output4
696441597

Data Constraint
特殊数据点数据范围

分析

考试的时候发现解决了 n = 1 n=1 n=1的情况就可以得60分( p = 1 p=1 p=1的时候输出 n = 1 n=1 n=1的结果即可),所以从 n = 1 n=1 n=1的情况入手。考虑只要有任意两个零级合成成功了就有了一级剑,否则就会少一个零级剑,少了一个零级剑就必须多买一个零级剑,那么 n = 1 n=1 n=1的期望就很简单了: E = 2 a ⋅ p + 3 a ⋅ ( 1 − p ) ⋅ p + 4 a ⋅ ( 1 − p ) 2 ⋅ p + ⋯ E=2a\cdot p+3a\cdot(1-p)\cdot p+4a\cdot(1-p)^2\cdot p+\cdots E=2ap+3a(1p)p+4a(1p)2p+
其中 p p p是合成成功的概率,即 min ⁡ { c 0 , b 0 } c 0 \dfrac{\min\{c_0,b_0\}}{c_0} c0min{c0,b0}
表示买两把零级剑就合成成功,买三把合成成功,买四把合成成功……的情况。

提个 a p ap ap E = a p lim ⁡ n → + ∞ [ 2 + 3 ( 1 − p ) + 4 ( 1 − p ) 2 + 5 ( 1 − p ) 3 + ⋯ + n ( 1 − p ) n − 2 ] E=ap\lim_{n\to +\infty}\left[2+3(1-p)+4(1-p)^2+5(1-p)^3+\cdots+n(1-p)^{n-2}\right] E=apn+lim[2+3(1p)+4(1p)2+5(1p)3++n(1p)n2]
t = 1 − p t=1-p t=1p,要化简的就是 S = lim ⁡ n → + ∞ ( 2 + 3 t + 4 t 2 + 5 t 3 + ⋯ + n t n − 2 ) S=\lim_{n\to +\infty}(2+3t+4t^2+5t^3+\cdots+nt^{n-2}) S=n+lim(2+3t+4t2+5t3++ntn2)


等比数列错位相减: ( t − 1 ) S = lim ⁡ n → + ∞ [ ( 2 t + 3 t 2 + 4 t 3 + 5 t 4 ⋯ + n t n − 1 ) − ( 2 + 3 t + 4 t 2 + 5 t 3 ⋯ + n t n − 2 ) ] = lim ⁡ n → + ∞ ( n t n − 1 − ∑ i = 1 n − 2 t i − 2 ) = lim ⁡ n → + ∞ ( n t n − 1 − t n − 1 − t t − 1 − 2 ) S = lim ⁡ n → + ∞ ( n t n − 1 − t n − 1 − t t − 1 − 2 ) t − 1 \begin{aligned} (t-1)S&amp;=\lim_{n\to +\infty}\left[(2t+3t^2+4t^3+5t^4\cdots+nt^{n-1})-(2+3t+4t^2+5t^3\cdots+nt^{n-2})\right]\\ &amp;=\lim_{n\to +\infty}(nt^{n-1}-\sum\limits_{i=1}^{n-2}t^i-2)\\ &amp;=\lim_{n\to +\infty}(nt^{n-1}-\dfrac{t^{n-1}-t}{t-1}-2)\\\\ S&amp;=\dfrac{\lim\limits_{n\to +\infty}(nt^{n-1}-\dfrac{t^{n-1}-t}{t-1}-2)}{t-1} \end{aligned} (t1)SS=n+lim[(2t+3t2+4t3+5t4+ntn1)(2+3t+4t2+5t3+ntn2)]=n+lim(ntn1i=1n2ti2)=n+lim(ntn1t1tn1t2)=t1n+lim(ntn1t1tn1t2)
显然 t &lt; 1 t&lt;1 t<1,所以 lim ⁡ n → + ∞ n t n − 1 = 0 \lim\limits_{n\to +\infty}nt^{n-1}=0 n+limntn1=0 lim ⁡ n → + ∞ t n − 1 = 0 \lim\limits_{n\to +\infty}t^{n-1}=0 n+limtn1=0,于是 S = t − 2 ( t − 1 ) 2 = 1 − p − 2 ( 1 − p − 1 ) 2 = p + 1 p 2 S=\dfrac{t-2}{(t-1)^2}=\dfrac{1-p-2}{(1-p-1)^2}=\dfrac{p+1}{p^2} S=(t1)2t2=(1p1)21p2=p2p+1


所以 E = a p ⋅ p + 1 p 2 = a p + 1 p E=ap\cdot\dfrac{p+1}{p^2}=a\dfrac{p+1}{p} E=app2p+1=app+1


在这个基础上考虑DP,设 d p [ i ] dp[i] dp[i]表示合成 i i i i &gt; 1 i&gt;1 i>1)级剑的期望花费,如果合成失败,相当于少了一把 i − 1 i-1 i1级剑,而对 i − 2 i-2 i2级剑没有影响,从概率上来说合成 1 p \dfrac{1}{p} p1 p p p i i i级剑合成成功的概率)次,就能合成成功,所以就要消耗 1 p \dfrac{1}{p} p1 i − 1 i-1 i1级剑,一把 i − 2 i-2 i2级剑,于是 d p [ i ] = 1 p d p [ i − 1 ] + d p [ i − 2 ] dp[i]=\dfrac{1}{p}dp[i-1]+dp[i-2] dp[i]=p1dp[i1]+dp[i2]


要用到逆元,每次 O ( log ⁡ n ) O(\log n) O(logn)求要T,所以要预先线性打逆元表

代码

#include<cstdio>
#include<algorithm>
using namespace std;

int read(){
    int x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=x*10+(c^48),c=getchar();
    return f?-x:x;
}

#define LL long long
#define MAXN 10000000
#define MOD 998244353
int N,A;
int B[MAXN+5],C[MAXN+5];

int Pow(int x,int y){
    int ret=1;
    while(y){
        if(y&1)
            ret=(LL)ret*x%MOD;
        y>>=1;
        x=(LL)x*x%MOD;
    }
    return ret;
}

#define MAXC 10000000
int Inv[MAXC+5];
void GetInv(int n){
    Inv[1]=1;
    for(int i=2;i<=n;i++)
        Inv[i]=(LL)Inv[MOD%i]*(MOD-MOD/i)%MOD;
}

LL dp[3];//滚动数组

int main(){
    freopen("forging.in" ,"r", stdin);
    freopen("forging.out","w",stdout);
    N=read(),A=read();
    GetInv(MAXC);
    int bx=read(),by=read(),cx=read(),cy=read(),p=read();
    B[0]=by+1,C[0]=cy+1;
    for(int i=1;i<N;i++){
        B[i]=((LL)B[i-1]*bx+by)%p+1;
        C[i]=((LL)C[i-1]*cx+cy)%p+1;
    }
    int k=min(C[0],B[0]);
    int P=(LL)k*Inv[C[0]]%MOD;
    dp[0]=A;
    dp[1]=(LL)A*(1+P)%MOD*Pow(P,MOD-2)%MOD;
    for(int i=2;i<=N;i++){
        k=min(C[i-1],B[i-2]);
        P=(LL)C[i-1]*Inv[k]%MOD;
        dp[i%3]=(dp[(i-1)%3]*P%MOD+dp[(i-2)%3])%MOD;
    }
    printf("%lld",dp[N%3]);
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值