ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[NOI2017] 泳池

2021-06-26 14:33:39  阅读:172  来源: 互联网

标签:矩形 int sum cdot NOI2017 bp MAXN 泳池


tag: 概率期望,dp,线性递推

一眼不可做,然后跳过

第一眼肯定枚举矩形,然后计算,然后发现十分不可做……因为要使你枚举的矩形最大而没有比它更大的,这个不太好用具体式子描述。

考虑转化为求 \([S\leq k]-[S\leq k-1]\),转化为所有矩形 $\leq k $,感觉可做一点了。

由于这道题只与长度有关系,设 \(f_i\) 表示底边为 \(i\) 的概率,转移的话就往后面拼一段联通块上去。

\(f_{i+j+1}=f_i+g_j\cdot(1-q)\),\(g_j\) 为概率,\(1-q\)是因为中间要空一列。

也就是说 \(f_i=\sum_{j=0}^k f_{i-j-1}\cdot g_j\cdot(1-q)\),看一眼数据范围矩阵快速幂 \(O(k^3logn)\) 是不行的,但是 \(O(k^2logn)\) 的常系数线性递推是可行的,所以问题转化为求 \(g_i\)。

对于一个联通块,可以看作是很多个矩形的并,但是仅仅 \(i\) 一维显然无法 \(dp\),所以考虑加一维 \(j\),设 \(h_{i,j}\) 表示最宽的那个矩形底边 \(=i\),高度为 \(j\)。

也就是说在高度为 \(j+1\) 的一行有至少一个危险区域,于是枚举第一个危险区域的位置 \(bp\) (假设当前区域为 \([1,i]\)),那么 \([1,bp-1]\) 这一段矩形的高度是大于 \(j\) 的(因为 \((bp,j+1)\) 是第一个危险区域),\([bp+1,i]\) 这一段的矩形则可以等于 \(j\)。

\[h_{i,j}=q^j(1-q)\sum_{bp=1}^i(\sum_{p>j}h_{bp-1,p})\cdot(\sum_{p\geq j}h_{i-bp,p})\quad\quad(i\cdot j\leq k) \]

合法的状态数为 \(\sum_i\left\lfloor\frac ki\right\rfloor=klnk\),一次转移复杂度 \(O(k)\) (用前缀和优化),于是计算 \(h_{i,j}\) 的复杂度为 \(O(k^2lnk)\)

总复杂度\(O(k^2logk-k^2logn)\)

#include<bits/stdc++.h>
using namespace std;

template<typename T>
inline void Read(T &n){
	char ch; bool flag=0;
	while(!isdigit(ch=getchar()))if(ch=='-')flag=1;
	for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
	if(flag)n=-n;
}

enum{
    MAXN = 1005,
    MOD = 998244353
};

inline int inc(int a, int b){
    a += b;
    if(a>=MOD) a -= MOD;
    return a;
}

inline void iinc(int &a, int b){a = inc(a,b);}

inline int dec(int a, int b){
    a -= b;
    if(a<0) a += MOD;
    return a;
}

inline void ddec(int &a, int b){a = dec(a,b);}

inline int ksm(int base, int k=MOD-2){
    int res = 1;
    while(k){
        if(k&1)
            res = 1ll*res*base%MOD;
        base = 1ll*base*base%MOD;
        k >>= 1;
    }
    return res;
}

int h[MAXN][MAXN], g[MAXN], S[MAXN][MAXN], f[MAXN];

int Pow[MAXN], n, k;

int F[MAXN<<2], G[MAXN<<2], Tmp[MAXN<<2];
inline int Solve(int n, int k){
    for(register int i=1; i<=k+1; i++) S[0][i] = 1; g[0] = 1;
    for(register int i=1; i<=k; i++){
        S[i][k/i+1] = 0;
        for(register int j=k/i; j; j--){
            int tmp = 0;
            for(register int bp=1; bp<=i; bp++)
                tmp = (tmp+1ll*S[bp-1][j+1]*S[i-bp][j])%MOD;
            h[i][j] = 1ll*tmp*Pow[j]%MOD*dec(1,Pow[1])%MOD;
            S[i][j] = inc(S[i][j+1],h[i][j]);
        }
        g[i] = S[i][1];
    }
    f[0] = 1;
    for(register int i=1; i<=k; i++){
        f[i] = g[i];
        for(register int j=0; j<=k and i-j-1>=0; j++) 
            f[i] = (f[i]+1ll*f[i-j-1]*g[j]%MOD*dec(1,Pow[1]))%MOD;
    }
    if(n<=k) return f[n];

    for(register int i=0; i<=k; i++) g[i] = 1ll*g[i]*dec(1,Pow[1])%MOD;
    memset(F,0,sizeof F); memset(G,0,sizeof G);
    F[1] = 1; G[0] = 1;
    while(n){
        if(n&1){
            for(register int i=0; i<=k; i++) for(register int j=0; j<=k; j++) Tmp[i+j] = (Tmp[i+j]+1ll*F[i]*G[j])%MOD;
            for(register int i=k+k; i>k; i--) if(Tmp[i]) for(register int j=0; j<=k; j++) Tmp[i-j-1] = (Tmp[i-j-1]+1ll*Tmp[i]*g[j])%MOD;
            for(register int i=0; i<=k; i++) G[i] = Tmp[i];
            for(register int i=0; i<=k+k; i++) Tmp[i] = 0;
        }
        for(register int i=0; i<=k; i++) for(register int j=0; j<=k; j++) Tmp[i+j] = (Tmp[i+j]+1ll*F[i]*F[j])%MOD;
        for(register int i=k+k; i>k; i--) if(Tmp[i]) for(register int j=0; j<=k; j++) Tmp[i-j-1] = (Tmp[i-j-1]+1ll*Tmp[i]*g[j])%MOD;
        for(register int i=0; i<=k; i++) F[i] = Tmp[i];
        for(register int i=0; i<=k+k; i++) Tmp[i] = 0;
        n >>= 1;
    }

    int ans=0; for(register int i=0; i<=k; i++) ans = (ans+1ll*G[i]*f[i])%MOD;

    return ans;
}

int main(){
    Read(n); Read(k); int tmpx, tmpy; Read(tmpx); Read(tmpy);
    Pow[0] = 1; Pow[1] = 1ll*tmpx*ksm(tmpy)%MOD; for(register int i=2; i<=k; i++) Pow[i] = 1ll*Pow[i-1]*Pow[1]%MOD;
    printf("%d\n",dec(Solve(n,k),Solve(n,k-1)));
    return 0;
}

标签:矩形,int,sum,cdot,NOI2017,bp,MAXN,泳池
来源: https://www.cnblogs.com/oisdoaiu/p/14934163.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有