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); } ```\]

  • 相关阅读:
    【转】VS2010中 C++创建DLL图解
    [转]error: 'retainCount' is unavailable: not available in automatic reference counting mode
    [转]关于NSAutoreleasePool' is unavailable: not available in automatic reference counting mode的解决方法
    【转】 Tomcat v7.0 Server at localhost was unable to start within 45
    【转】Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If
    【转】SVN管理多个项目版本库
    【转】eclipse安装SVN插件的两种方法
    【转】MYSQL启用日志,和查看日志
    【转】Repository has not been enabled to accept revision propchanges
    【转】SVN库的迁移
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12721932.html
Copyright © 2011-2022 走看看