zoukankan      html  css  js  c++  java
  • ! 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);
    }
    
  • 相关阅读:
    yolo_to_onnx ValueError: need more tan 1 value to unpack
    yolo_to_onnx killed
    C++ 实现二维矩阵的加减乘等运算
    Leetcode 1013. Partition Array Into Three Parts With Equal Sum
    Leetcode 1014. Best Sightseeing Pair
    Leetcode 121. Best Time to Buy and Sell Stock
    Leetcode 219. Contains Duplicate II
    Leetcode 890. Find and Replace Pattern
    Leetcode 965. Univalued Binary Tree
    Leetcode 700. Search in a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12579961.html
Copyright © 2011-2022 走看看