题意:
有一个长度为
的序列,序列上每个位置有一个物品,每个物品在每次被询问到的时候有
的概率被拒绝,考虑这样一个过程:先取前
个物品,然后每次对这
个物品都询问,如果有
个物品被拒绝,则将前
个物品丢弃,然后从未被选取的物品中选取最靠前的
个物品重复这个过程,当总物品数
时停止,问期望询问多少组次。
,
可以写出
表示现在手上的物品是
时期望还需要多少步。
下面那个可以简单
计算,
上面那个。。。
凭什么这个
要平白无故地处理多个多项式还开
你可以拿起笔,在草稿纸上涂涂画画,写下一堆形如“
”的东西,然后拍案而起:“不会做,自闭了,我要去洗澡!”
你也可以平心静气,突然发现,唉,上面的多项式长得都差不多啊,然后安静地度过一天。
其实上面那个式子是可以分治
的。
首先差卷积不太爽,我们将
翻转,那么我们实际上也就是把
也翻转了,最后的答案就是
。
设
则在
时
时
其中
然后考虑自顶向下的分治
。
当前我们在
,拥有
和
那么可以发现如果
,则
就是我们想要的东西,求个第
项即可。
考虑怎么在走到
和
的时候快速的维护出
。
当
变成
时,可以发现我们可以直接
当
变成
时,我们可以直接
把后面的全部分治
预处理出来即可简单转移、
但是当你写出上面的式子的时候你就
了,所谓细节调一年。
上面的式子其实应该是:
然后你仔细思考这个取
和取
,
以取
为例:
当
时,
若
则原多项式为
。
否则,只有一个
可以使得
。
对于这种情况直接再暴力一个自下而上的分治
再算一遍即可。(但是好像网上其他解法有些可以避开这种情况的高论。)
其他情况可以一个自下而上的分治
搞定。
还有一些细节比如说
我们应该只保留次数在
之间的项来保证复杂度正确。
对于
只保留次数在
之间的项。
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define maxn 800005
#define Ct const
#define LL long long
#define pii pair<int,int>
#define vc vector
#define vi vc<int>
#define mod 998244353
#define pb push_back
#define mp make_pair
#define db double
using namespace std;
namespace IO{
char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){
char ch;bool f=0;
for(;!isdigit(ch=getc());) if(ch=='-') f=1;
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
(f) && (res = -res);
}
}
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod; return r; }
int n,L,p[maxn],f[maxn],*F[maxn],*G[maxn];
int *P[maxn],*P2[maxn];
int Wl,Wl2,w[maxn],lg[maxn],inv[maxn],fac[maxn],invf[maxn];
void init(int n){
for(Wl=1;n>=Wl<<1;Wl<<=1);
int pw = Pow(3 , (mod-1) / (Wl2=Wl<<1));
w[Wl] = inv[0] = inv[1] = fac[0] = fac[1] = invf[0] = invf[1] = 1;
rep(i,Wl+1,Wl2) w[i] = 1ll * w[i-1] * pw % mod;
per(i,Wl-1,1) w[i] = w[i<<1];
rep(i,2,Wl2) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod,fac[i] = 1ll * fac[i-1] * i % mod,
invf[i] = 1ll * invf[i-1] * inv[i] % mod , lg[i] = lg[i >> 1] + 1;
}
int upd(int x){ return x += x >> 31 & mod; }
void NTT(int *A,int n,int tp){
static int r[maxn]={};
static unsigned long long ar[maxn];
if(tp ^ 1) reverse(A+1,A+n);
rep(i,0,n-1) r[i] = r[i >> 1] >> 1 | (i&1) << lg[n] - 1 , ar[i] = upd(A[r[i]]);
for(int L=1;L<n;L<<=1) for(int s=0,L2=L<<1;s<n;s+=L2) for(int k=s,x=L,t;k<s+L;k++,x++)
t=w[x]*ar[k+L]%mod,ar[k+L]=ar[k]-t+mod,ar[k]+=t;
rep(i,0,n-1) A[i] = ar[i] % mod;
if(tp ^ 1) rep(i,0,n-1) A[i] = 1ll * A[i] * inv[n] % mod;
}
void Mul(int *A,int *B,int *C,int n,int m,int shift = 0,int cut = 0x3f3f3f3f){
static int st[2][maxn];
int L = 1 << lg[n+m] + 1;
rep(i,0,L-1) st[0][i] = i <= n ? A[i] : 0 ,
st[1][i] = i <= m ? B[i] : 0;
NTT(st[0],L,1) , NTT(st[1],L,1);
rep(i,0,L-1) st[0][i] = 1ll * st[0][i] * st[1][i] % mod;
NTT(st[0],L,-1);
rep(i,shift,min(cut,n+m)) C[i - shift] = st[0][i];
}
#define lc u<<1
#define rc lc|1
int *B[maxn];
void Build2(int u,int l,int r){
B[u] = new int [r - l + 2];
if(l == r) return (void)(B[u][0] = 1 - p[l] , B[u][1] = p[l]);
int m = l + r >> 1;
Build2(lc,l,m) , Build2(rc,m+1,r);
Mul(B[lc],B[rc],B[u],m-l+1,r-m);
}
void Build(int u,int l,int r){
P[u] = new int [r-l+2];
P2[u] = new int [r-l+2];
F[u] = new int [4 * (r-l+2)];
G[u] = new int [4 * (r-l+2)];
memset(P[u],0,sizeof (int) * (r-l+2));
memset(P2[u],0,sizeof (int) * (r-l+2));
memset(F[u],0,sizeof (int) * 4 * (r-l+2));
memset(G[u],0,sizeof (int) * 4 * (r-l+2));
if(l == r) return (void)(
P[u][0] = 1 - p[l+1] , P[u][1] = p[l+1] ,
P2[u][0] = 1 - (l - L >= 1 ? p[l - L] : 0) , P2[u][1] = (l - L >= 1 ? p[l-L] : 0)
);
int m = l + r >> 1;
Build(lc,l,m) , Build(rc,m+1,r);
Mul(P[lc],P[rc],P[u],m-l+1,r-m);
Mul(P2[lc],P2[rc],P2[u],m-l+1,r-m);
if(l + L < r){
memset(P2[rc],0,4 * (r-m+1));
if(l + L <= m){
P2[rc][0] = 1;
}
else{
Build2(1,max(m+1-L,1),l);
rep(i,0,l-max(m+1-L,1)+1) P2[rc][i] = B[1][i];
}
}
if(r - L + 1 > l + 1){
//printf("#%d %d\n",l,r);
memset(P[lc],0,4 * (m-l+2));
if(r - L + 1 > m + 1){
P[lc][0] = 1;
}
else{
Build2(1,r-L+1,m+1);
rep(i,0,m+1-(r-L+1)+1) P[lc][i] = B[1][i];
}
}
}
void Solve(int u,int l,int r){
if(l == r){
//printf("@%d %d %d\n",l,r,F[u][1]);
f[l] = 1ll * f[l] * (1 + F[u][1]) % mod;
return;
}
int m = l + r >> 1;
Mul(F[u],P2[rc],F[lc],2*(r-l+1)-1,r-m,r-m,r-m+(m-l+1)*2);
Mul(G[u],P2[rc],G[lc],2*(r-l+1)-1,r-m,0,(m-l+1)*2);
Solve(lc,l,m);
static int t[maxn];
Mul(G[u],P[lc],G[rc],2*(r-l+1)-1,m+1-l,0,(r-m)*2);
Mul(F[u],P[lc],F[rc],2*(r-l+1)-1,m+1-l,(m+1-l)*2,(m+1-l)*2 + (r-m)*2);
Mul(&f[l],G[rc],t,m-l,(r-m)*2);
rep(i,0,(r-m)*2) F[rc][i+(l+r-2*m-1)] = (F[rc][i+(l+r-2*m-1)] + t[i]) % mod /*, printf("@%d %d %d\n",i,(l+r-2*m-1),t[i])*/;
Solve(rc,m+1,r);
}
int main(){
freopen("friends.in","r",stdin);
freopen("friends.out","w",stdout);
scanf("%d%d",&n,&L);
int sm = 1;
rep(i,1,n){
int a,b;scanf("%d%d",&a,&b);
p[i] = 1ll * a * Pow(b , mod - 2) % mod;
}
reverse(p+1,p+n+1);
rep(i,1,n){
sm = 1ll * sm * (1 - p[i]) % mod * (i - L >= 1 ? Pow(1 - p[i-L] , mod-2) : 1) % mod;
if(i >= L) f[i] = Pow(1 - sm , mod-2);
}
init(n << 2);
Build(1,1,n);
G[1][0] = 1;
Solve(1,1,n);
printf("%d\n",(f[n]+mod)%mod);
}