zoukankan      html  css  js  c++  java
  • 题解 「BJOI2018 治疗之雨」

    题目传送门

    题目大意

    有一个初始为 (p) 的数,每次操作分为以下两个:

    • (frac{1}{m+1}) 的概率$+1,但是中途 (p) 的最大值只能为 (n)$

    • (k) 次减少操作,每次有 (frac{1}{m+1}) 的概率 (-1)

    (每次先操作操作 (1) 然后操作操作 (2)

    (p) 变为 (0) 的期望操作次数。

    (T) 次询问,每次保证 (1le ple nle 1500,m,kle 10^9),答案对 (10^9+7) 取模。

    思路

    其实这道题很水,也不知道怎么评到黑题的。

    首先,我们可以发现,(k) 次被打中 (i) 次的概率为 (frac{inom{k}{i}m^{k-i}}{(m+1)^k}) ,也就是说我们可以算出一次操作由 (i) 变为 (j) 的概率,我们假设这个为 (p_{i,j})

    然后我们发现肯定可以设 (f_i) 表示当前值为 (i) 的剩余期望操作次数,我们可以得到转移式:

    [f_i=sum_{j=0}^{i+1}p_{i,j} imes f_j+1 ]

    [Rightarrow f_{i+1}=frac{1}{p_{i,i+1}}(f_i-1-sum_{j=0}^{i}p_{i,j} imes f_j) ]

    然后你发现这个东西可以用一个套路做了,就是说我们发现每一个 (f_i) 我们都可以表示为 (a imes f_1+b) 的形式,然后我们递推一下解个方程就可以求出 (f_1) 继而求出答案了。

    时间复杂度 (Theta(Tnlog n))

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000007
    #define MAXN 1505
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int mul (int a,int b){return 1ll * a * b % mod;}
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    int qkpow (int a,int b){
    	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
    	return res;
    }
    int inv (int x){return qkpow (x,mod - 2);}
    
    int n,m,k,st,invx,invm,ci[MAXN],binom[MAXN];
    
    int calc (int x){//计算k轮中减少x的概率 
    	if (x < 0 || x > k) return 0;
    	else return mul (binom[x],mul (ci[x],invx));
    }
    
    int pro (int i,int j){
    	if (i == n) return calc (i - j); 
    	else return add (mul (calc (i - j),dec (1,invm)),mul (calc (i - j + 1),invm));
    }
    
    struct node{
    	int k,b;//表示为k*f[1]+b
    	node (){}
    	node (int _k,int _b){k = _k,b = _b;}
    	node operator + (int x){return node (k,add (b,x));} 
    	node operator - (int x){return node (k,dec (b,x));}
    	node operator * (int x){return node (mul (k,x),mul (b,x));}
    	node operator + (node x){return node (add (k,x.k),add (b,x.b));}
    	node operator - (node x){return node (dec (k,x.k),dec (b,x.b));}
    }f[MAXN];
    
    signed main(){
    	int T;read (T);
    	while (T --> 0){
    		read (n,st,m,k),invx = inv (qkpow (m + 1,k)),invm = inv (m + 1);
    		if (!k){puts ("-1");continue;}
    		if (!m){
    			if (k == 1) puts ("-1");
    			else{
    				int cnt = 0;
    				while (st > 0) cnt ++,st = min (n,st + 1) - k;
    				write (cnt),putchar ('
    ');
    			}
    			continue;
    		}
    		binom[0] = 1;for (Int i = 1;i <= n;++ i) binom[i] = mul (binom[i - 1],mul (k - i + 1,inv (i)));
    		for (Int i = 0;i <= n && i <= k;++ i) ci[i] = qkpow (m,k - i);
    		f[1] = node (1,0);
    		for (Int i = 1;i <= n - 1;++ i){
    			f[i + 1] = node (0,0);
    			for (Int j = 1;j <= i;++ j) f[i + 1] = f[i + 1] + f[j] * pro (i,j);
    			f[i + 1] = (f[i] - 1 - f[i + 1]) * inv (pro (i,i + 1));
    		}
    		node sum = node (0,0);
    		for (Int i = 1;i <= n;++ i) sum = sum + f[i] * pro (n,i);
    		sum = f[n] - 1 - sum;int f1 = mul (mod - sum.b,inv (sum.k));
    		write (add (f[st].b,mul (f1,f[st].k))),putchar ('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    陶哲轩实分析习题17.3.3
    陶哲轩实分析定理17.3.8 (二)
    《陶哲轩实分析》引理17.2.4证明_导数的唯一性
    陶哲轩实分析定理17.3.8(一)
    陶哲轩实分析定理17.3.8(一)
    《陶哲轩实分析》引理17.2.4证明_导数的唯一性
    键值对在架构设计里的应用
    来自Google、Amazon和Facebook等7大知名互联网的系统扩展经验
    对象的消息模型
    Google的系统工程师(SA)如何工作
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13638247.html
Copyright © 2011-2022 走看看