zoukankan      html  css  js  c++  java
  • 【CF1194F】Crossword Expert(数学 期望)

    题目链接

    大意

    给你(N)个事件,解决每个事件所需的时间有(1/2)的概率为(t[i])(1/2)的概率为((t[i]+1)),给你总时间(T),在(T)时间内按顺序解决事件,求能解决的事件的期望个数。
    (答案对(10^9+7)取模)

    ((Nle 2cdot 10^5,1le t[i]le 10^9,1le Tle 2cdot 10^{14}))

    思路

    考虑如何求期望:
    我们设(P[i])表示第(i)件物品能被做完的概率。
    则有$$Ans=sum_{i=1}^{N}P[i]$$

    则问题就转化为如何求(P[i])

    我们设(Sum[i])表示前(i)件事的最小时间和,即(Sum[i]=sum_{i=1}^{N}t[i])

    ①:对于(Sum[i]+ile T)的情况:
    则第(i)件事一定会被做完,故(P[i]=1)

    ②:对于(Sum[i]le T<Sum[i]+i)的情况:
    我们设(Dp[i][j])表示前(i)件事有(j)件事时间多做了(1)个单位的概率,即多做了(j)个时间单位,
    则对于每个(Dp[i][j]),若有(Sum[i]+j<=T),则可以对(P[i])产生(Dp[i][j])的贡献。

    考虑如何求(Dp[i][j])
    将这些事件按是否多做(1)个时间单位分类,
    若完成时间为(t[i]),则类型为(0)
    若完成时间为(t[i]+1),则类型为(1)
    则可以将这些事件的状态表示为一个(01)串。
    则总状态数就为(2^i),从(i)个数中选(j)个让其状态为(1)的个数就为(C(i,j))
    (Dp[i][j]=frac{C(i,j)}{2^i})

    对于每个(P[i])
    我们倘若每次都去枚举有哪些(j)是可以满足(Sum[i]+j<=T)的话,很明显会超时。
    则考虑如何从上一次((P[i-1]))所需的状态数转到(P[i])的状态数。
    (注:第一次进入情况②的时候可以暴力找到状态)

    考虑如何快速地从(P[i-1])转移到(P[i])的状态:
    我们设上一次需要的(C)是从(C(i-1,0))(C(i-1,Sum_K))
    设上一次的(P[i-1]=frac{Sum_N}{2^{i-1}}),则有(Sum_N=sum_{j=0}^{Sum_K}C(i-1,j))

    根据$$C(i,j)=C(i-1,j)+C(i-1,j-1)$$
    则有$$sum_{j=1}{Sum_K}C(i,j)=sum_{j=1}{Sum_K}(C(i-1,j)+C(i-1,j-1))$$
    则$$sum_{j=1}{Sum_K}C(i,j)=(2*sum_{j=0}{Sum_K}C(i-1,j))-C(i-1,0)-C(i-1,Sum_K)$$

    然后,对于这次的(Sum_N)来说,
    (Sum_N=sum_{j=1}^{Sum_K}C(i,j)+C(i,0)-sum_{j=T-Sum[i]+1}^{Sum_K}C(i,j))
    (Sum_N=(2*sum_{j=0}^{Sum_K}C(i-1,j))-C(i-1,Sum_K)-sum_{j=T-Sum[i]+1}^{Sum_K}C(i,j))
    (Sum_N=Sum_N*2-C(i-1,Sum_K)-sum_{j=T-Sum[i]+1}^{Sum_K}C(i,j))
    则这一次的(Sum_N)就可以从上一次的(Sum_N)转移过来。
    显然这一次的(Sum_K=T-Sum[i])
    (Sum_K)会随着(i)的增大而减小,
    而进入情况②的条件是:(Sum[i]<=T<Sum[i]+i)
    即求解所有的(Sum_N)的时间复杂度总计(O(N))

    ③:(Sum[i]>T)
    则事件(i)一定不会被做完,即(P[i]=0)

    综上,(Ans)得解。

    代码

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define LL long long
    const int ON=200000;
    const int MAXN=200005;
    const long long ONE=1;
    const int MOD=1000000007;
    int N,t[MAXN];
    long long F[MAXN];
    long long T,Sum[MAXN],Ans;
    long long f[MAXN]={1},fe[MAXN]={1};
    long long O[MAXN]={1},Oe[MAXN]={1};
    long long Sum_N,Sum_K;
    LL quick_Pow(LL x,LL y){
    	if(y==0)return 1;
    	if(y==1)return x;
    	if(y%2)return (x*quick_Pow((x*x)%MOD,y/2))%MOD;
    	return quick_Pow((x*x)%MOD,y/2);
    }
    void Prepare(){
    	for(int i=1;i<=ON;i++){
    		f[i]=(f[i-1]*i)%MOD;
    		fe[i]=quick_Pow(f[i],MOD-2);
    		O[i]=(O[i-1]*2)%MOD;
    		Oe[i]=quick_Pow(O[i],MOD-2);
    	}
    }
    long long C(long long x,long long y){
    	if(y>x)return 0;
    	return (f[x]*((fe[y]*fe[x-y])%MOD))%MOD;
    }
    long long work(long long n,long long k){
    	if(Sum_K==0){
    		for(int i=0;i<=k;i++)
    			Sum_N=(Sum_N+C(n,i))%MOD;
    	}else{
    		Sum_N=(Sum_N*2-C(n-1,Sum_K)+MOD)%MOD;
    		for(int i=Sum_K;i>k;i--)
    			Sum_N=(Sum_N-C(n,i)+MOD)%MOD;
    	}
    	Sum_K=k;
    	return Sum_N;
    }
    int main(){
    	Prepare();
    	scanf("%d%lld",&N,&T);
    	for(int i=1;i<=N;i++){
    		scanf("%d",&t[i]);
    		Sum[i]=Sum[i-1]+t[i];
    	}
    	for(int i=1;i<=N;i++){
    		if(Sum[i]>T)break;
    		if(Sum[i]+i<=T){
    			F[i]=1;
    			continue;
    		}
    		F[i]=(work(i,T-Sum[i])*Oe[i])%MOD;
    	}
    	for(int i=1;i<=N;i++)
    		Ans=(Ans+F[i])%MOD;
    	printf("%lld
    ",Ans);
    }
    
  • 相关阅读:
    sql 查询服务器硬盘剩余空间
    SQL语句导致cpu占用如此高
    (@WhiteTaken)Unity中Invoke的用法
    (@WhiteTaken)设计模式学习——抽象工厂模式
    (@WhiteTaken)设计模式学习——工厂方法模式
    (@WhiteTaken)设计模式学习——简单工厂模式
    c#中的泛型委托(@WhiteTaken)
    c#中@的作用
    lua读书笔记(@WhiteTaken)
    Unity中的预制的Attributes
  • 原文地址:https://www.cnblogs.com/ftotl/p/11597633.html
Copyright © 2011-2022 走看看