【JZOJ 4938】序列(70分做法)

Description

这里写图片描述

Solution

设DP方程: fi 表示做到i且i位为0的和期望, gi 表示做到i且i位为0的和期望平方,
sum(i,j)=(i+j)(ij+1)/2
先看一下f怎么求,

fi=j=0i1(fj+sum(j+1,i1))(1pj)k=j+1i1pk

这个很好理解,
有公式: (a+b)2=a2+b2+2ab
所有g的求法也和上面的差不多,就是加上了完全平方公式,
gi=j=0i1(gj+sum(j+1,i1)2+2sum(j+1,i1)fj)(1pj)k=j+1i1pk

最后输出 gn+1

复杂度: O(n2) (辣鸡只会70分)

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int N=2e6+50,mo=998244353;
int read(LL &n)
{
    char ch=' ';LL q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,m;
LL p[N],p1[N];
LL ps[N],psn[N];
LL f[N],g[N];
int ts[N];
LL ksm(LL q,LL w)
{
    LL a=q%mo,ans=1;
    while(w)
    {
        if(w%2) ans=(ans*a)%mo;
        a=(a*a)%mo;w=w/2;
    }
    return(ans);
}
int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    LL q,w,yb=ksm(100,mo-2);
    n=read(q);
    psn[0]=ps[0]=1;p[0]=0;p1[0]=1;
    fo(i,1,n)p1[i]=(100-read(p[i]))*yb%mo,p[i]=p[i]*yb%mo;
    p[n+1]=0;p1[n+1]=1;
    fo(i,1,n+1)
    {
        ts[i]=ts[i-1];
        if(p[i])ps[i]=p[i]*ps[i-1]%mo;else ps[i]=ps[i-1],ts[i]++;
        psn[i]=ksm(ps[i],mo-2);
    }
    ts[n+1]--;
    fo(i,1,n+1)
    {
        fo(j,0,i-1)if(ts[i-1]-ts[j]<1)
        {
            q=(i-j)*(i-j-1)/2%mo;w=(i-j)*(i-j-1)%mo;
            f[i]=(f[i]+(f[j]+q)*p1[j]%mo*(ps[i-1]*psn[j]%mo)%mo)%mo;
            g[i]=(g[i]+(g[j]+f[j]*w%mo+q*q%mo)%mo*p1[j]%mo*(ps[i-1]*psn[j]%mo)%mo)%mo;
        }
    }
    printf("%lld\n",g[n+1]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值