[codeforces722E] Research Rover

来源:互联网 发布:微软办公软件mac版 编辑:程序博客网 时间:2024/06/05 02:53

题目大意

有一个n*m的网格图,你要从(1,1)走到(n,m),每一步可以向右(或向下)走。你最开始有s点能量,然而有k个障碍点,每到达一个障碍点,你的能量会变成x2。问走到(n,m)时你最终能量的期望。假设它是PQ,输出PQ1109+7的逆元。

数据范围

n,m≤100000 k≤2000 1≤s≤1000000

分析

首先可以发现,s最终变成1后,一直变化都是1,所以s最多只有logs个取值。
把障碍点排序,这是一定要的。并且把(n,m)也看成障碍点
然后可以设f[i][j]表示走到第j个障碍点,经过i个障碍点的答案。我们发现如果求每个点两两之间不经过任何其它障碍点的答案较难,所以可以考虑容斥。
设g[i][j],j和上面一样,i表示经过至少i个障碍点。容易求出f[0]、g[0]的值。然后对于i>0转移如下:
g[i][j]=f[i1][k]Ways[k][j]
f[i][j]=g[i][j]f[i][k]Ways[k][j]
其中Ways[i][j]表示i到j的方案数,这个组合数算一下就好了。

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#define fi first#define se secondusing namespace std;const int maxs=2005,maxn=200005,mo=1e9+7,N=22;typedef long long LL;typedef double db;typedef pair<int,int> PII;int n,m,k,s,M,Energy[N],f[N][maxs],g[N][maxs],All[maxs][maxs],Fac[maxn],Fac_Inv[maxn],Inv[maxn],ans;PII Point[maxs];char c;int read(){    for (c=getchar();c<'0' || c>'9';c=getchar());    int x=c-48;    for (c=getchar();c>='0' && c<='9';c=getchar()) x=x*10+c-48;    return x;}bool cmp(PII a,PII b){    return a.fi<b.fi || a.fi==b.fi && a.se<b.se;}void Init(){    n=read(); m=read(); k=read(); s=read();    for (int i=1;i<=k;i++)    {        Point[i].fi=read()-1; Point[i].se=read()-1;    }    sort(Point+1,Point+k+1,cmp);    Point[++k].fi=n-1; Point[k].se=m-1;    Point[0].fi=Point[0].se=0;    Fac[0]=Fac_Inv[0]=Fac[1]=Fac_Inv[1]=Inv[1]=1;    for (int i=2;i<=n+m;i++)    {        Fac[i]=(LL)Fac[i-1]*i%mo;        Inv[i]=(LL)Inv[mo%i]*(mo-mo/i)%mo;        Fac_Inv[i]=(LL)Fac_Inv[i-1]*Inv[i]%mo;    }    Energy[0]=s;    while (s>1) Energy[++M]=s=ceil((db)s/2);}int Comb(int N,int M){    return (LL)Fac[N]*Fac_Inv[M]%mo*Fac_Inv[N-M]%mo;}void Work(){    for (int i=1;i<=k;i++)    {        f[0][i]=g[0][i]=Comb(Point[i].fi+Point[i].se,Point[i].fi);        for (int j=1;j<i;j++)            if (Point[i].se>=Point[j].se)            {                All[j][i]=Comb(Point[i].fi-Point[j].fi+Point[i].se-Point[j].se,Point[i].fi-Point[j].fi);                f[0][i]=(f[0][i]+mo-(LL)f[0][j]*All[j][i]%mo)%mo;            }    }    for (int i=1;i<=M;i++)    {        for (int j=i+1;j<=k;j++)        {            for (int x=i;x<j;x++) if (Point[x].se<=Point[j].se)                g[i][j]=(g[i][j]+(LL)f[i-1][x]*All[x][j])%mo;            f[i][j]=g[i][j];            for (int x=i;x<j;x++) if (Point[x].se<=Point[j].se)                f[i][j]=(f[i][j]+mo-(LL)f[i][x]*All[x][j]%mo)%mo;        }    }    ans=0;    for (int i=0;i<M;i++) ans=(ans+(LL)Energy[i]*f[i][k]%mo)%mo;    ans=(ans+g[M][k])%mo;    ans=(LL)ans*Fac[n-1]%mo*Fac[m-1]%mo*Fac_Inv[n+m-2]%mo;    printf("%d\n",ans);}int main(){    Init();    Work();    return 0;}
1 0