把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5472】[NOI2019] 斗主地(猜结论)

点此看题面

  • 有一个\(n\)张牌的牌堆,初始从上往下依次编号\(1\sim n\),编号为\(i\)的牌的权值为\(x^{ty}\)
  • \(m\)轮洗牌,第\(i\)次会先将牌堆最上面\(a_i\)张牌取出另成一堆。假设当前两堆分别剩余\(X,Y\)张牌,则会以\(\frac X{X+Y}\)的概率取出第一堆最下面的牌,或以\(\frac Y{X+Y}\)的概率取出第二堆最下面的牌,放在新牌堆的最上面。
  • \(q\)次询问,每次询问最后的第\(i\)张牌权值的期望。
  • \(n\le10^7,m\le5\times10^5,ty=1\ or\ 2\)

非常玄学的猜结论题

这道题的核心结论:一次函数洗牌之后的期望还是一次函数,二次函数洗牌后的期望还是二次函数

证明暂且不会,先坑了。(话说如果真在考场上遇到这种题目,真不知道自己有没有猜结论并相信自己的结论的自信。。。)

如果这个结论是正确的,那么\(m\)次洗牌之后得到的仍应是一次函数/二次函数,也就是说我们只要任选三个好算的位置算一算就好了。

首先第一个位置和最后一个位置肯定是很好算的,那么我们再添上第二个位置就凑齐三个位置了。

转移很显然:

\[x_1=x_1\times \frac an+x_{a+1}\times\frac {n-a}n\\ x_n=x_a\times\frac an+x_n\times\frac{n-a}n\\ x_2=x_2\times\frac{a-1}{n-1}\times\frac an+x_{a+1}\times\frac{n-a}{n-1}\times\frac an+x_{1}\times\frac{a}{n-1}\times\frac{n-a}n+x_{a+2}\times\frac{n-a-1}{n-1}\times\frac{n-a}n \]

发现分母实际上只有\(n\)\(\frac1{(n-1)n}\),可以实现预处理避免复杂度平添一个\(log\)

而要由三个值解出一个二次函数,只要列出三个方程:

\[\begin{cases} A+B+C=x_1,\\ 4A+2B+C=x_2,\\ n^2A+nB+C=x_n \end{cases} \Rightarrow \begin{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('\n');}
}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;//代入函数中计算值
}
posted @ 2021-04-08 11:37  TheLostWeak  阅读(60)  评论(0编辑  收藏  举报