! BJOI2018治疗之雨


高斯消元算DP

(f_i)表示k次减血减(i)滴血的概率

(f_i=frac{C_k^im^{k-i}}{(m+1)^k})可以递推求出

然后方程的系数就很好算了

血量减爆的情况只与(E_0)的系数有关,但(E_0=0)所以不用管

等等,(n=1500)怎么高斯消元?

发现矩阵呈近似下三角矩阵

110000

111000

111100

111110

111111

111111

每行我们就只消两列,把上述矩形消成

(具体来说应该是一列一列地消,只是消到那一行时,就只有两个未知量了,用来消别的行)

110000

011000

001100

000110

000011

000001

最后一行只有一个未知量,可以回代求解

(实在扯不清楚就只能看代码了)

时间复杂度(O(n^2))

还有一种方法,移项后发现f[1]只和f[2]相关,因此设f[1]=x

其他未知量都可以通过x表示出来,代到f[n]的方程里就解出x

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1504,mod=1e9+7;
int n,p,m,k,inv,inv1,a[N][N],f[N];
inline int ksm(int x,int r){
	int ret=1;
	for(int i=0;(1ll<<i)<=r;i++){
		if((r>>i)&1)ret=ret*x%mod;
		x=x*x%mod; 
	}
	return ret;
}
inline void solve(){
	n=read();p=read();m=read();k=read();
	if(!k){puts("-1");return;}
	if(!m){
		if(k==1){puts("-1");return;}
		int ret=0;
		for(;p>0;p-=k,ret++)
			if(p<n)p++;
		cout<<ret<<"
";
		return;
	}
	inv=ksm(m,mod-2);inv1=ksm(m+1,mod-2);
	f[0]=ksm(m*inv1%mod,k);
	for(int i=1;i<=min(n+1,k);i++)
		f[i]=f[i-1]*inv%mod*ksm(i,mod-2)%mod*(k-i+1)%mod;
	for(int i=1;i<n;i++)
		for(int j=1;j<=i;j++)
			a[i][j]=(f[i-j]*m+f[i-j+1])%mod*inv1%mod;
	for(int i=1;i<n;i++)
		a[i][i+1]=f[0]*inv1%mod;
	for(int i=1;i<=n;i++)
		a[i][n+1]=mod-1;
	for(int i=1;i<=n;i++)
		a[n][i]=f[n-i];
	for(int i=1;i<=n;i++)
		a[i][i]=(a[i][i]+mod-1)%mod;
	
	for(int i=1,tmp;i<=n;i++){//两列两列消 
		inv=ksm(a[i][i],mod-2);
		a[i][i]=1;
		a[i][n+1]=a[i][n+1]*inv%mod;
		if(i!=n)a[i][i+1]=a[i][i+1]*inv%mod;
		for(int j=i+1;j<=n;j++){
			tmp=a[j][i];
			a[j][i+1]=(a[j][i+1]-tmp*a[i][i+1]%mod+mod)%mod;
			a[j][n+1]=(a[j][n+1]-tmp*a[i][n+1]%mod+mod)%mod;
		}
	}
	for(int i=n;i>1;i--)
		a[i-1][n+1]=(a[i-1][n+1]-a[i-1][i]*a[i][n+1]%mod+mod)%mod;
	cout<<a[p][n+1]<<"
";
}
inline void clear(){
	for(int i=1;i<=min(n+1,k);i++)f[i]=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n+1;j++)a[i][j]=0;
}
signed main(){
	int T=read();
	while(T--){
		solve(); 
		clear();
	}
	return (0-0);
}
原文地址:https://www.cnblogs.com/aurora2004/p/12579961.html