期望题集--[BJOI2018]治疗之雨

xiaoxiao2025-10-12  19

题目链接:https://www.luogu.org/problemnew/show/P4457

发现不能直接记忆化搜索,因为当前可能状态可能转移到血量+1的状态,但可以发现如果血量为上限值时就没有这种情况了,因此先写出每一个状态的转移式,为一串其他状态*系数+常数,然后从第n位下来把每一个状态转移式中>=当前状态血量的状态消去,再dfs即可。

代码:

#include<bits/stdc++.h> #define ll long long using namespace std; const ll mod=1e9+7; const int N=1510; ll n,p,m,k,f[N],xs[N][N],cs[N],C[N],jc[N],ijc[N],X,Y,g[N]; void Ad(ll &x,ll y) {x+=y;if(x>=mod)x-=mod;} void Dw(ll &x,ll y) {x=(x>=y)?x-y:x-y+mod;} ll qpow(ll x,ll y) { ll res=1; while(y) { if(y&1)res=res*x%mod; x=x*x%mod,y>>=1; } return res; } void f__k(int x) { ll tp; if(xs[x][x+1]) { tp=xs[x][x+1]; xs[x][x+1]=0; for(int i=x;i>=0;i--) Ad(xs[x][i],tp*xs[x+1][i]%mod); Ad(cs[x],tp*cs[x+1]%mod); } if(xs[x][x]) { tp=1; Dw(tp,xs[x][x]); tp=qpow(tp,mod-2); xs[x][x]=0; for(int i=0;i<x;i++) xs[x][i]=xs[x][i]*tp%mod; cs[x]=cs[x]*tp%mod; } } void get_xs(ll x) { for(int i=0;i<=min(k,x);i++) xs[x][x+1-i]=X*Y%mod*C[i]%mod*g[i]%mod; for(int i=0;i<=min(k,x);i++) Ad(xs[x][x-i],m*Y%mod*X%mod*C[i]%mod*g[i]%mod); cs[x]=1; } ll dfs(int nw) { if(f[nw]!=-1)return f[nw]; f[nw]=cs[nw]; for(int i=nw-1;i>=0;i--) Ad(f[nw],xs[nw][i]*dfs(i)%mod); return f[nw]; } bool check() { if(k==0)return 1; if(m==0) { if(k==1) { if(n>1)return 1; } } return 0; } int main() { int T;ll tp; jc[0]=1; for(int i=1;i<N;i++) jc[i]=jc[i-1]*i%mod; ijc[N-1]=qpow(jc[N-1],mod-2); for(int i=N-2;i>=0;i--) ijc[i]=ijc[i+1]*(i+1)%mod; scanf("%d",&T); while(T--) { scanf("%lld%lld%lld%lld",&n,&p,&m,&k); if(check()){puts("-1");continue;} memset(xs,0,sizeof xs),memset(cs,0,sizeof cs); for(int i=0;i<=p;i++)f[i]=-1;f[0]=0,tp=1; for(int i=0;i<=n&&i<=k;i++) { C[i]=tp*ijc[i]%mod; tp=tp*(k-i)%mod; } X=qpow(m+1,k),X=qpow(X,mod-2),Y=qpow(m+1,mod-2); for(int i=0;i<=n&&i<=k;i++) g[i]=qpow(m,k-i); for(int j=0;j<=min(k,n);j++) xs[n][n-j]=X*C[j]%mod*g[j]%mod; cs[n]=1,f__k(n); for(int i=n-1;i>=1;i--) get_xs(i),f__k(i); printf("%lld\n",dfs(p)); } }

 

转载请注明原文地址: https://www.6miu.com/read-5037790.html

最新回复(0)