- 有一个(n)张牌的牌堆,初始从上往下依次编号(1sim n),编号为(i)的牌的权值为(x^{ty})。
- 有(m)轮洗牌,第(i)次会先将牌堆最上面(a_i)张牌取出另成一堆。假设当前两堆分别剩余(X,Y)张牌,则会以(frac X{X+Y})的概率取出第一堆最下面的牌,或以(frac Y{X+Y})的概率取出第二堆最下面的牌,放在新牌堆的最上面。
- (q)次询问,每次询问最后的第(i)张牌权值的期望。
- (nle10^7,mle5 imes10^5,ty=1 or 2)
非常玄学的猜结论题
这道题的核心结论:一次函数洗牌之后的期望还是一次函数,二次函数洗牌后的期望还是二次函数。
证明暂且不会,先坑了。(话说如果真在考场上遇到这种题目,真不知道自己有没有猜结论并相信自己的结论的自信。。。)
如果这个结论是正确的,那么(m)次洗牌之后得到的仍应是一次函数/二次函数,也就是说我们只要任选三个好算的位置算一算就好了。
首先第一个位置和最后一个位置肯定是很好算的,那么我们再添上第二个位置就凑齐三个位置了。
转移很显然:
[x_1=x_1 imes frac an+x_{a+1} imesfrac {n-a}n\
x_n=x_a imesfrac an+x_n imesfrac{n-a}n\
x_2=x_2 imesfrac{a-1}{n-1} imesfrac an+x_{a+1} imesfrac{n-a}{n-1} imesfrac an+x_{1} imesfrac{a}{n-1} imesfrac{n-a}n+x_{a+2} imesfrac{n-a-1}{n-1} imesfrac{n-a}n
]
发现分母实际上只有(n)和(frac1{(n-1)n}),可以实现预处理避免复杂度平添一个(log)。
而要由三个值解出一个二次函数,只要列出三个方程:
[egin{cases}
A+B+C=x_1,\
4A+2B+C=x_2,\
n^2A+nB+C=x_n
end{cases}
Rightarrow
egin{cases}
A=frac{(n-2)x_1-(n-1)x_2+x_n}{n^2-3n+2},\
B=x_2-x_1-3A,\
C=x_1-A-B
end{cases}
]
分母同样可以预处理。
所以说这道题的难点就在于最开始洗牌之后函数次数不变的结论,之后的过程真就超级简单了。
代码:(O(m+q))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define X 998244353
using namespace std;
int n,m,ty;I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
namespace FastIO
{
#define FS 100000
#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
');}
}using namespace FastIO;
int A,B,C;I int F(CI x) {return (1LL*A*x%X*x+1LL*B*x+C)%X;}//计算F(x)的值
int IV;I void Calc(CI x,CI y,CI z) {A=(1LL*(n-2)*x%X-1LL*(n-1)*y%X+z+X)*IV%X,B=(y-x-3LL*A+4LL*X)%X,C=(x-A-B+2LL*X)%X;}//解方程
int main()
{
read(n,m,ty);RI iv=QP(n,X-2),iv_=1LL*iv*QP(n-1,X-2)%X;IV=QP((1LL*n*n-3*n+2)%X,X-2);//预处理分母
RI i,a,x=1,y=QP(2,ty),z=QP(n,ty);for(i=1;i<=m;++i) read(a),Calc(x,y,z),//求出二次函数
x=(1LL*F(1)*a+1LL*F(a+1)*(n-a))%X*iv%X,z=(1LL*F(a)*a+1LL*F(n)*(n-a))%X*iv%X,//求出新的x1,xn
y=((1LL*F(2)*(a-1)+1LL*F(a+1)*(n-a))%X*a+(1LL*F(1)*a+1LL*F(a+2)*(n-a-1))%X*(n-a))%X*iv_%X;//求出新的x2
RI Qt;read(Qt),Calc(x,y,z);W(Qt--) read(a),writeln(F(a));return clear(),0;//代入函数中计算值
}