您的位置:首页 > 其它

[codeforces722E] Research Rover

2016-10-27 17:22 127 查看

题目大意

有一个n*m的网格图,你要从(1,1)走到(n,m),每一步可以向右(或向下)走。你最开始有s点能量,然而有k个障碍点,每到达一个障碍点,你的能量会变成⌈x2⌉。问走到(n,m)时你最终能量的期望。假设它是PQ,输出P∗Q−1模109+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[i−1][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 second

using 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
,f
[maxs],g
[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
*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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: