[NOI2019]斗主地

终于做出了这个把我送退役的结论题。

由于是均匀混合,所以所有排列出现的概率相同。

考场上我写了30分的O(mn^2)暴力,然后发现:E[ai]仍然为一次、二次函数。这个可以用期望的线性性解释。

定义E[ai]=f(i),f(i)为关于i的一/二次函数,然后经过操作为k的变化,左边第i项变成f(i),右边第i项变成f(k+i),然后求出左边、右边(用插值)前三项即可。

#include<bits/stdc++.h>
typedef long long ll;
const int mod=998244353,inv2=499122177;
int n,m,A,Q,tp;
int E1, E2, E3;
ll i0,i1,i2;
int qpow(int a,int b)
{
    int ret=1;
    while(b)
    {
        if(b&1)ret=1ll*ret*a%mod;
        a=1ll*a*a%mod,b>>=1;
    }
    return ret;
}
int calc(int i)
{
    if(i==1)return E1;
    if(i==2)return E2;
    if(i==3)return E3;
    int s1=1ll*E1*(i-2)%mod*(i-3)%mod,s2=1ll*E2*(2-2*i+mod)%mod*(i-3)%mod,s3=1ll*E3*(i-1)%mod*(i-2)%mod;
    return(1ll*s1+s2+s3)*inv2%mod;
}
int main()
{
    scanf("%d%d%d",&n,&m,&tp),--tp;
    i0=qpow(n,mod-2),i1=qpow(1ll*n*(n-1)%mod,mod-2),i2=qpow(1ll*n*(n-1)%mod*(n-2)%mod,mod-2);
    E1=1,E2=tp?4:2,E3=tp?9:3;
    while(m--)
    {
        scanf("%d",&A);
        ll f1=E1,f2=E2,f3=E3,f4=calc(A+1),f5=calc(A+2),f6=calc(A+3);
        E1=(f1*A+f4*(n-A))%mod*i0%mod;
        E2=(f2*A%mod*(A-1)+(f1+f4)*A%mod*(n-A)+f5*(n-A)%mod*(n-A-1))%mod*i1%mod;
        E3=(f3*A%mod*(A-1)%mod*(A-2)+(f4+2*f2)*A%mod*(A-1)%mod*(n-A)+(2*f5+f1)*A%mod*(n-A)%mod*(n-A-1)%mod+f6*(n-A)%mod*(n-A-1)%mod*(n-A-2))%mod*i2%mod;
    }
    scanf("%d",&Q);
    int X;while(Q--)scanf("%d",&X),printf("%d\n",calc(X));
}
View Code

 

posted @ 2020-08-06 15:45  hfctf0210  阅读(213)  评论(0编辑  收藏  举报