zoukankan      html  css  js  c++  java
  • 「NOI2017」泳池

    「NOI2017」泳池

    可以发现每一列出现指定高度的安全位置的概率是可以预处理的,设概率为\(w_i\)

    由于连续面积不超过\(k\),所以我们可以优先预处理出连续\(k\)个以内高度\(>0\)的方案数

    要求连续\(k\)个高度\(>0\)的,我们还可以进一步降维,求连续\(k/2\)\(>1\),然后继续递归。。。

    每次转移都是一段从上一层转移下来然后,紧接着一段是空的

    最终迭代得到\(A[i]\)表示连续\(i\)个高度\(>0\)的列的概率,复杂度\(O(k^2\ln k)\)(以下)

    可以得到最终的\(dp\)转移方程

    \[dp_i=\sum_1^kdp_{i-j}A_{j-1}w_0$$表示我们强制这一位是空的 可以发现这是一个简单的线性递推关系,如果使用矩阵优化,可以做到$O(k^3)logn$ 正解我们要用到 **[常系数线性齐次递推](https://www.luogu.com.cn/problem/P4723)** 表示我特别喜欢用vector实现多项式问题。。。 很多大佬的板子都经过卡常,可读性并不是太高。。。 ```cpp #include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define reg register typedef long long ll; #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i) #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i) #define pb push_back template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); } template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); } char IO; template<class T=int> T rd(){ T s=0; int f=0; while(!isdigit(IO=getchar())) if(IO=='-') f=1; do s=(s<<1)+(s<<3)+(IO^'0'); while(isdigit(IO=getchar())); return f?-s:s; } const int N=(1<<10)+10,P=998244353; ll qpow(ll x,ll k){ ll res=1; for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P; return res; } namespace Polynomial{ int rev[N<<2]; void NTT(int n,vector <int> &a,int f){ rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]); for(int i=1;i<n;i<<=1){ ll w=qpow(f==1?3:(P+1)/3,(P-1)/i/2); for(int l=0;l<n;l+=i*2){ ll e=1; for(int j=l;j<l+i;++j,e=e*w%P) { ll t=a[j+i]*e%P; a[j+i]=(a[j]-t+P)%P; a[j]=(a[j]+t)%P; } } } if(f==-1){ ll t=qpow(n,P-2); rep(i,0,n-1) a[i]=a[i]*t%P; } } int PreMake(int n){ int R=1,cc=-1; while(R<=n) R<<=1,cc++; rep(i,1,R-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<cc); return R; } vector <int> operator * (vector <int> a,vector <int> b){ int n=a.size()+b.size()-1,R=PreMake(n); a.resize(R),b.resize(R); NTT(R,a,1),NTT(R,b,1); rep(i,0,R-1) a[i]=1ll*a[i]*b[i]%P; NTT(R,a,-1); return a; } vector <int> Inv(vector <int> a,int n){ if(n==1){ vector <int> tmp; tmp.pb(qpow(a[0],P-2)); return tmp; } a.resize(n); vector <int> b=Inv(a,(n+1)>>1); int R=PreMake(n*2); a.resize(R),b.resize(R); NTT(R,a,1),NTT(R,b,1); rep(i,0,R-1) b[i]=(P+2-1ll*a[i]*b[i]%P)*b[i]%P; NTT(R,b,-1); b.resize(n); return b; } vector <int> operator / (vector <int> a,vector <int> b) { int n=a.size(),m=b.size(); reverse(a.begin(),a.end()),reverse(b.begin(),b.end()); b.resize(n-m+1); b=Inv(b,n-m+1), a=a*b; a.resize(n-m+1); reverse(a.begin(),a.end()); return a; } vector <int> operator - (vector <int> a,vector <int> b){ int sz=max(a.size(),b.size()); a.resize(sz),b.resize(sz); rep(i,0,a.size()-1) a[i]=(a[i]-b[i]+P)%P; return a; } vector <int> operator % (vector <int> a,vector <int> b){ a=a-a/b*b; a.resize(b.size()-1); return a; } void Show(vector <int> a){ for(int i:a) printf("%d ",i); puts(""); } int st[N]; } using namespace Polynomial; int n,k; ll p; ll w[N],s[N],t[N],h[N],dp[N]; ll Calc(int k) { memset(s,0,sizeof s),memset(t,0,sizeof t); drep(i,k,1) { if(i==k) { t[1]=w[k]; continue; } memset(s,0,sizeof s),memset(h,0,sizeof h); s[0]=1; rep(j,0,k/i) { rep(d,j+1,k/i) { if(d==j+1) s[d]=(s[d]+s[j]*w[i])%P; else s[d]=(s[d]+s[j]*w[i]%P*t[d-j-1])%P; } } rep(j,0,k/i) { h[j]=(h[j]+s[j])%P; rep(d,j+1,k/i) h[d]=(h[d]+s[j]*t[d-j])%P; } memcpy(t,h,sizeof t); } memcpy(s,t,sizeof t); dp[0]=s[0]=1; rep(i,0,k) s[i]=s[i]*w[0]%P; drep(i,++k,1) s[i]=s[i-1]; rep(i,1,N-1) { dp[i]=0; rep(j,max(i-k,0),i-1) dp[i]=(dp[i]+dp[j]*s[i-j])%P; } if(n+1<N) return dp[n+1]*qpow(w[0],P-2)%P; int p=n+1; vector <int> Mod,x,res; drep(i,k,1) Mod.pb(s[i]); rep(i,0,Mod.size()-1) Mod[i]=(P-Mod[i])%P; Mod.pb(1); x.resize(k),x[1]=1,res.resize(k),res[0]=1; for(;p;p>>=1,x=x*x%Mod) if(p&1) res=res*x%Mod; ll ans=0; rep(i,0,k-1) ans=(ans+1ll*res[i]*dp[i])%P; ans=ans*qpow(w[0],P-2)%P; return ans; } int main(){ n=rd(),k=rd(); p=rd(),p=p*qpow(rd(),P-2)%P; w[0]=(P+1-p)%P; rep(i,1,k) w[i]=w[i-1]*p%P; if(n==1) { printf("%lld\n",w[k]); return 0; } printf("%lld\n",(Calc(k)-Calc(k-1)+P)%P); } ```\]

  • 相关阅读:
    Orcle 导入数据eurusd.ctl
    Maven系列2pom.xml 配置详解
    UML关联&泛化的区别
    maven 创建工程
    maven 打包
    jprofiler安装和配置
    设计模式出现之前的几大原则
    检查启动情况linux
    领域模型
    解压命令tar
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12721932.html
Copyright © 2011-2022 走看看