codeforces 1194F Crossword Expert

题目链接:https://codeforc.es/contest/1194/problem/F  (中国镜像网站)

题目链接:https://codeforces.com/contest/1194/problem/F

 

题目大意:每个任务会耗时t或者t+1秒。求规定时间会完成任务个数的期望。

PS:碰到好题了,分享一下。

 

思路:可以看出第i任务对答案的期望为(杨辉三角的第i层的前(t-Sum)项的和)/(2的i次方)。Sum是前i个任务规定时间的总和。

0、Sum会越来越大(废话)

1、(t-Sum)<0,该任务对答案没有奉献。(比如样列1的第三个任务。不管怎么样都不会完成这个任务的。)

2、(t-Sum)>=i,该任务一定会发生。比如样列1的第一个任务。

3、(t-Sum),会越来越小

4、跟据以上三条。发现我们要求的层数是一段连续的层数,并且要求的前(t-Sum)项会越来越少。直到(t-Sum)<0;

证明:概率论的二项式定理看懂了就会了,(杨辉三角的第n层的前k项和)/(2的i次方)等价于抛硬币n次的正面次数不多于k的概率。

 

通过预处理,可以得到n的阶层,n的阶层的逆元。就可以O(1)的求组合函数C(a,b)的值。

所以这个题可以O(n^2)解决了。(通过枚举需要求的第i层的前(t-Sum)项)

PS:比赛是这样写然后超时了。555~~

然后赛后补题发现,组合函数有这个公式

然后,发现,(第n层的前k项和)*2-C(k,n)==(第n+1层的前k项和)。

证明:

 

然后就好办了。

1、暴力枚举我们的第一次要求的层数的前(t-Sum)项。

2、根据上述结论算出下一层的前(t-Sum0)项。( (t-Sum0)是上一层的(t-Sum)。加个0以示区别 )

3、然后减去不这一层不要的后面几项。

4、重复2,3直到结束或者(t-Sum)<0。

 

结束。贴代码。嘻嘻嘻。

#include <bits/stdc++.h>
using namespace std;
#define N 100010
#define int long long
#define mod 1000000007
#define mp make_pair
#define endl '\n'
#define IOS cin.sync_with_stdio(false);cin.tie(0);cout.tie(0);
int A[200010],A_inv[200010];
void init1(){
    int p=mod;
    A_inv[1]=1;
    for(int i=2;i<=200005;++i){
        A_inv[i] = ((p-(p / i)) * A_inv[p % i]%p+p)%p;
    }
    for(int i=2;i<=200005;++i){
        A_inv[i]*= (A_inv[i-1]);
        A_inv[i]%=mod;
    }
    A[0]=1;
    for(int i=1;i<=200005;++i){
        A[i]=A[i-1]*i%mod;
    }
}
int Sum_c;
int Sum_i0;
int C(int n,int i0){
    if(Sum_c==0){
        Sum_c=1;
        for(int i=1;i<=i0;i++){
            Sum_c+=A[n]*A_inv[n-i]%mod*A_inv[i]%mod;
            Sum_c%=mod;
        }
        Sum_i0=i0;
    }
    else{
        int n0=n-1;
        Sum_c=Sum_c*2-A[n0]*A_inv[n0-Sum_i0]%mod*A_inv[Sum_i0]%mod+mod;
        Sum_c%=mod;
        for(;Sum_i0>i0;Sum_i0--){
            Sum_c=Sum_c-A[n]*A_inv[n-Sum_i0]%mod*A_inv[Sum_i0]%mod+mod;
            Sum_c%=mod;
        }
    }
    return Sum_c;
}
int power(int a,int b){
    int ret=1;
    for(int k=a;b;b>>=1,k=k*k%mod){
        if(b&1){
            ret=ret*k%mod;
        }
    }
    return ret;
}
 
signed main(){
init1();IOS;
    int n,t,a;
    cin>>n>>t;
    int Ans=0;
    int rk=1;
    int Sum=0;
    for(int i=1;i<=n;i++){
        rk<<=1;
        rk%=mod;
        cin>>a;
        Sum+=a;
        if(Sum+i<=t){
            Ans++;
            Ans%=mod;
        }
        else if(Sum>t){
            break;
        }
        else{
            Ans+=C(i,t-Sum)*power(rk,mod-2);
            Ans%=mod;
        }
    }
    cout<<Ans;
    return 0;
}
/*
 
*/

 

posted @ 2019-07-15 19:50  opooopooo  阅读(248)  评论(0编辑  收藏  举报