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
*/