2019.8.4中山纪中提高A组题解

锻造 (forging)

题目描述

在这里插入图片描述在这里插入图片描述
Input
第一行两个整数 n, a,含义如题所示。
为了避免输入量过大,第二行五个整数 bx, by, cx, cy, p,按照下列代码
来生成 b 和 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 Input

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 Output

Sample Output1
6432

Sample Output2
150643649

Sample Output3
976750710

Sample Output4
696441597

Data Constraint
在这里插入图片描述


题解

不知道为什么,看到概率就会想到 D p Dp Dp
当然这道题显然是一道 D p Dp Dp
因为在考场上我对这道题极其有研究,所以讲得稍微详细一点。
虽然这道题很简单,但是我们从头开始(但是我太菜了)。
首先看到 n = 0 n=0 n=0,直接就是 a a a嘛没什么可说的。
然后想了一下暂时还有点懵逼(开始读题读错了)。

于是考虑 n = 1 n=1 n=1
我们先定义一下(方便表示): f [ i ] f[i] f[i]表示得到一把 i i i级剑的期望花费
显然 f [ 0 ] = a f[0]=a f[0]=a
这里我们想到这个操作可以失败的次数是不确定的,既是我们假设我们经过 i − 2 i-2 i2次失败后成功,既是需要 i i i 0 0 0级剑,然后这种情况对最后答案的贡献是:
( 1 − p ) i − 2 × p × i × f [ 0 ] (1-p)^{i-2} \times p \times i \times f[0] (1p)i2×p×i×f[0]
可以得到
f [ 1 ] = ∑ i = 2 + ∞ p × ( 1 − p ) i − 2 × i × f [ 0 ] f[1]=\sum\limits_{i=2}^{+\infty}p\times(1-p)^{i-2}\times i \times f[0] f[1]=i=2+p×(1p)i2×i×f[0]
x = 1 − p x=1-p x=1p,即
f [ 1 ] = p × f [ 0 ] × ∑ i = 2 + ∞ i × x i − 2 f[1]=p\times f[0]\times\sum\limits_{i=2}^{+\infty}i\times x^{i-2} f[1]=p×f[0]×i=2+i×xi2
所以我们就是要求
∑ i = 2 + ∞ i × x i − 2 \sum\limits_{i=2}^{+\infty}i\times x^{i-2} i=2+i×xi2
S = ∑ i = 2 + ∞ i × x i − 2 = 2 x 0 + 3 x 1 + 4 x 2 + . . . . . . + n x n − 2 S=\sum\limits_{i=2}^{+\infty}i\times x^{i-2}=2x^{0}+3x^{1}+4x^{2}+......+nx^{n-2} S=i=2+i×xi2=2x0+3x1+4x2+......+nxn2
x S = 2 x 1 + 3 x 2 + 4 x 3 + . . . . . . + ( n − 1 ) x n − 2 + n x n − 1 xS=2x^{1}+3x^{2}+4x^{3}+......+(n-1)x^{n-2}+nx^{n-1} xS=2x1+3x2+4x3+......+(n1)xn2+nxn1
( x − 1 ) S = n x n − 1 − ( x 1 + x 2 + . . . . . . + x n − 2 ) − 2 (x-1)S=nx^{n-1}-(x^{1}+x^{2}+......+x^{n-2})-2 (x1)S=nxn1(x1+x2+......+xn2)2
( x − 1 ) S = n x n − 1 − x n − 1 − x x − 1 − 2 (x-1)S=nx^{n-1}-\dfrac{x^{n-1}-x}{x-1}-2 (x1)S=nxn1x1xn1x2
S = n x n − ( n + 1 ) x n − 1 − x + 2 ( x − 1 ) 2 S=\dfrac{nx^{n}-(n+1)x^{n-1}-x+2}{(x-1)^2} S=(x1)2nxn(n+1)xn1x+2
因为 n → + ∞ , 0 &lt; x &lt; 1 n\to +\infty,0&lt;x&lt;1 n+,0<x<1,所以 n x n → 0 , ( n + 1 ) x n − 1 → 0 nx^{n}\to0,(n+1)x^{n-1}\to0 nxn0,(n+1)xn10
S = 2 − x ( x − 1 ) 2 S=\dfrac{2-x}{(x-1)^{2}} S=(x1)22x
p = 1 − x p=1-x p=1x代入 S S S
S = 1 + p p 2 S=\dfrac{1+p}{p^{2}} S=p21+p
所以 f [ 1 ] = f [ 0 ] × 1 + p p f[1]=f[0]\times \dfrac{1+p}{p} f[1]=f[0]×p1+p

于是 n = 1 n=1 n=1就处理完了,我们再看看还有什么是容易做的。
看到有 p = 1 p=1 p=1再一想,就是除了合成1级剑,其它都是一定成功。
就很容易了。
d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i]=dp[i-1]+dp[i-2] dp[i]=dp[i1]+dp[i2]
其中 d p [ 0 ] 和 d p [ 1 ] dp[0]和dp[1] dp[0]dp[1]知道。

所以我们已经有60分了,NICE
开始考虑正解。
发现每一次合成一把 i i i级剑,都是要用 x { x ∈ [ 1 , + ∞ ] } x \{x\in[1,+\infty]\} x{x[1,+]} i − 1 i-1 i1级剑和1把 i − 2 i-2 i2级剑。
类比考虑合成1级剑的过程,我们得到
f [ i ] = f [ i − 2 ] + ∑ x = 1 + ∞ f [ i − 1 ] × x × ( 1 − p ) x − 1 × p f[i]=f[i-2]+\sum_{x=1}^{+\infty} f[i-1]\times x \times (1-p)^{x-1}\times p f[i]=f[i2]+x=1+f[i1]×x×(1p)x1×p
大家自己对照前面的过程化简一下会得到
f [ i ] = f [ i − 2 ] + f [ i − 1 ] p f[i]=f[i-2]+\dfrac{f[i-1]}{p} f[i]=f[i2]+pf[i1]
这本身也是可以理解的。
再加一个逆元就好了。
要线性筛逆元不然会T。
线性筛逆元


代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=int(1e7+5);
typedef long long LL;
#define mod 998244353
LL n,a;
LL b[MAXN];
LL c[MAXN];
LL dp[MAXN];
LL XINV[MAXN+5];
LL Pow(LL a,LL b) {
    long long ret=1,x=(long long)a,y=(long long)b;
    while(y) {
        if(y%2)
          ret=ret*x%mod;
        y/=2;
        x=(x*x)%mod;
    }
    return LL(ret)%mod;
}
LL Inv(LL a) {
    return Pow(a,mod-2);
}
void Prepare() {
    XINV[1]=1;
    for(int i=2;i<=MAXN;i++)
        XINV[i]=XINV[mod%i]*(mod-mod/i)%mod;
}
int main()
{
    Prepare();
    freopen("forging.in","r",stdin);
    freopen("forging.out","w",stdout);
    LL bx,by,cx,cy,p;
    scanf("%lld%lld",&n,&a);
    scanf("%lld%lld%lld%lld%lld",&bx,&by,&cx,&cy,&p);
    b[0]=by+1,c[0]=cy+1;
    for(LL 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;
    }
    if(n==0) {
        printf("%lld",a);
        return 0;
    }
    else if(p==1||n==1) {
        LL inv=XINV[c[0]],Min=min(c[0],b[0]);
        LL P=(LL)inv*Min%mod;
        LL ans=(LL)a*(1+P)%mod*Inv(P)%mod;
        dp[0]=a,dp[1]=ans;
        for(LL i=2;i<=n;i++)
            dp[i]=(dp[i-1]+dp[i-2])%mod;
        printf("%lld",dp[n]);
    }
    else {
        LL inv=XINV[c[0]],Min=min(c[0],b[0]);
        LL P=(LL)inv*Min%mod;
        LL ans=(LL)a*(1+P)%mod*Inv(P)%mod;
        dp[0]=a,dp[1]=ans;
        for(LL i=2;i<=n;i++) {
            LL MIN=min(c[i-1],b[i-2]);
            LL INV=XINV[MIN];
            dp[i]=((LL)dp[i-1]*c[i-1]%mod*INV%mod+dp[i-2])%mod;
        }
        printf("%lld",dp[n]);
    }
}

如果MLE就把一些LL改为int


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值