【JZOJ】6271. 锻造 (forging)

Description

Time Limits: 1500 ms Memory Limits: 262144 KB

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


思路

对于每次合成x级(x>=2),是使用x-1,x-2级武器各一把来合。
设P为合成x级成功的概率,那么有:
概率为P合成x级,概率为(1-P)合成x-1级。
对于概率为(1-P)时,此次合成相当于浪费一把(x-2)级的武器。

dp[i]表示合成第i级武器的期望花费。
则有:dp[i]=dp[i-1]+dp[i-2]*(1/P)
其中1/P为合成次数的期望值,表示合了这么多次后,终于成功。

但是这题卡常,得先线性求一波逆元,转移时O(1)使用。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
const long long ONE=1;
const int MAXN=10000007;
const int MOD=998244353;
int bx,by,cx,cy,p;
int N,A,b[MAXN],c[MAXN];
long long dp[MAXN],f[MAXN];
long long quick_Pow(long long x,int y){
	if(y==0)return 1;
	if(y==1)return x;
	if(y%2)return (x*quick_Pow((x*x)%MOD,y/2))%MOD;
	return quick_Pow((x*x)%MOD,y/2);
}
long long P(int i){
	if(i==0)return (c[0]*f[min(b[0],c[0])])%MOD;
	if(c[i]<=b[i-1])return 1;
	else return (c[i]*f[b[i-1]])%MOD;
}
int main(){
	freopen("forging.in","r",stdin);
	freopen("forging.out","w",stdout);
	f[0]=0;f[1]=1;
	for(int i=2;i<=1e7;i++)
		f[i]=MOD-(((MOD/i)*f[MOD%i])%MOD);
	scanf("%d%d",&N,&A);
	scanf("%d%d%d%d%d",&bx,&by,&cx,&cy,&p);
	b[0]=by+1;c[0]=cy+1;
	for(int i=1;i<N;i++){
		b[i]=(ONE*b[i-1]*bx+by)%p+1;
		c[i]=(ONE*c[i-1]*cx+cy)%p+1;
	}
	dp[0]=A;
	if(N>=1)dp[1]=(P(0)*dp[0]+dp[0])%MOD;
	for(int i=2;i<=N;i++)
		dp[i]=(dp[i-2]+dp[i-1]*P(i-1))%MOD;
	printf("%lld\n",dp[N]);
}
/*
0 6432
4602677 3944535 2618884 6368297 9477531

1 3639650
6136976 5520115 2835750 9072363 9302097

10 2
2 33 6 66 2333333

200 5708788
0 0 0 0 1
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值