链接:https://www.nowcoder.com/acm/contest/197/C
来源:牛客网
题目描述
Nqijij 有一个数x,和一个神秘权值 q, 满足 x <= q, 每一次nqijij会随机x 变成 [x, q] 中的一个随机数,nqijij想要知道期望多少次操作之后x 变为q。
由于nqijij 是一个精力充沛的人,所以他总共会选择 T 次x 和q 进行操作,对于每一次操作,你需要输出期望多少次操作之后x 变为q 在 998244353 模意义下的值。
(令 ans = x / y, x, y 为正整数且 题目保证 x、y 与998244353 互质,则输出x * (y^(-1)), (y^(-1)) 表示y在998244353下的乘法逆元,可以证明这样的逆元存在)
题目保证 T <= 1e6, q <= 1e7, x <= 1e7;
输入描述:
第一行一个数T 接下来T行 每行两个整数 x, q (x <= q)
输出描述:
输出T行 第 i 行的正整数 表示第i次询问的答案。
示例1
输入
复制
2 7 8 15 18
输出
复制
2 831870297
说明
对于第一个样例 每一次有0.5的概率结束利用简单的求和可知是2.
递推求逆元模板
//求逆元,当n特别大时,效果特别好
//begin
LL inv[N];
inline void get_inv()
{
inv[1] = 1;
for(int i=2; i<N; i++) {
if(i >= mod) break;
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
}
//end
对于这种无限次的选择,自己就会很懵逼,其实直接求确实是不存在,但是我们可以
1.找到状态表示,找到递推式
2.给定初始值
然后我们推一下就好了,基本上都是很简单的,不要恐惧
这道题,我们可以考虑,有用的就是两个人之间的差值。
所以我们假设 结尾在q,
那么我可以在
1, 用 f[1] 表示从1点到 n点的期望步数,
可以得到
在2的时候,可以得到
在其他点同理。 然后倒着退回来就好了。
可能那个1比较难理解,我们可以换个角度,如果我们想去q的话,是可以1步直接到的. 要考虑特殊点,特殊值,要不然,没有出口了,递归不能终止了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=b-1;i>=a;--i)
#define clk clock()
const int mod=998244353;
const int N=1e7+10;
LL f[N];
LL inv_mod(LL base,int n)
{
LL ans=1;
while(n) {
if(n&1)ans=ans*base%mod;
base=base*base%mod;
n>>=1;
}
return ans%mod;
}
//求逆元,当n特别大时,效果特别好
//begin
LL inv[N];
inline void get_inv()
{
inv[1] = 1;
for(int i=2; i<N; i++) {
if(i >= mod) break;
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
}
//end
int main()
{
//double t1=clk;
//for(int i=1;i<N;i++)inv[i]=inv_mod(i,mod-2);//求逆元超时,nlog(n) 也是太高
get_inv();
f[1]=2;
LL sum=f[1];
for(int i=2; i<N; i++) {
f[i]=(sum+i+1)%mod*inv[i]%mod;
sum=sum+f[i];
if(sum>=mod)sum-=mod;
}
//double t2=clk;
//printf("%.2f\n",(t2-t1)/CLOCKS_PER_SEC);
int T;
scanf("%d",&T);
while(T--) {
int x,q;
scanf("%d %d",&x,&q);
if(q==x) {
puts("0");
} else {
printf("%d\n",f[q-x]);
}
}
return 0;
}