您的位置:首页 > 其它

Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) E

2016-10-08 19:28 417 查看
题意:

一艘飞往火星的飞船,,,,可以看成它现在在一个n*m的网格里,现在在位置(1,1),目标是位置(n,m),它会随机选一条到达(n,m)的最短路出发,这个网格有k个特别的点,这些点的道路崎岖坎坷--以至于当飞船经过这些点的时候,会消耗一半的电量,初始时飞船电量为s,设当前剩余电量为x,经过一个特别点,电量变成

,询问从起点到终点路径上的期望剩余电量,答案mod
1E9 + 7输出




solution:


ans是个分数P/Q的形式,P是所有方案的剩余电量之和,Q是方案数。因为每次经过特殊点剩余电量/2,因此,经过特殊点次数超过20次的,剩余电量总是1。。现在,如果能统计出少于20次的各种方案,答案也就解决了

从(r1,c1)到(r2,c2),方案数是C(r2 - r1 + c2 - c1,c2 - c1)证明用隔板法,记作path(r1,c1,r2,c2)

将所有特殊点按照两个坐标升序排序,这样第i个点可能到达的点一定是属于(i,k]

考虑第i个点到达终点,不经过其它点的方案数,记作Fi

Fi = path(ri,ci,n,m) - ∑path(ri,ci,rj,cj)*Fj  (j∈(i,k])

这样每条多余的路只会被减去一遍,当且仅当j是这条路的最后一个点

令Gi,v:从第i个点出发,到达终点,除了第i个点外,经过v个点的方案数

Gi,0 = Fi

Gi,v = path(ri,ci,n,m) - ∑Gi,j (j∈[0,v)) - ∑path(ri,ci,rj,cj)*Gj,v(j∈(i,k])

这样长度大于v的路径只会被减一次,证明同上,长度小于v的路径,显然只会被减一次

将(1,1)也考虑成关键点,用上述公式递推之即可



#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int mo = 1E9 + 7;
const int maxn = 2E5 + 20;

struct Point{
int r,c;
Point(){}
Point(int r,int c): r(r),c(c){}
bool operator < (const Point &b) const {
if (r < b.r) return 1;
if (r > b.r) return 0;
return c < b.c;
}
}p[maxn];

int n,m,k,s,ans,fac[maxn],inv[maxn],f[maxn],g[maxn][22];

int path(int r1,int c1,int r2,int c2)
{
int x = r2 - r1;
int y = c2 - c1;
if (x < 0 || y < 0) return 0;
return 1LL*fac[x+y]*inv[y]%mo*inv[x]%mo;
}

int ksm(int x,int y)
{
int ret = 1;
for (; y; y >>= 1) {
if (y&1) ret = 1LL*ret*x%mo;
x = 1LL*x*x%mo;
}
return ret;
}

int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif

cin >> n >> m >> k >> s;
for (int i = 1; i <= k; i++) {
int x,y;
scanf("%d%d",&x,&y);
p[i] = Point(x,y);
}
fac[0] = 1;
for (int i = 1; i <= n + m; i++)
fac[i] = 1LL*i*fac[i-1]%mo;
inv[n+m] = ksm(fac[n+m],mo-2);
for (int i = n + m - 1; i >= 0; i--)
inv[i] = 1LL*(i+1)*inv[i+1]%mo;
p[++k] = Point(1,1);
sort(p + 1,p + k + 1);
for (int i = k; i; i--) {
int T = path(p[i].r,p[i].c,n,m);
f[i] = T;
for (int j = i + 1; j <= k; j++) {
f[i] -= 1LL*path(p[i].r,p[i].c,p[j].r,p[j].c)*f[j]%mo;
f[i] = (f[i] + mo) % mo;
}
g[i][0] = f[i];
for (int v = 1; v <= 20; v++) {
g[i][v] = T;
for (int j = i + 1; j <= k; j++) {
g[i][v] -= 1LL*path(p[i].r,p[i].c,p[j].r,p[j].c)*g[j][v]%mo;
g[i][v] = (g[i][v] + mo) % mo;
}
for (int j = 0; j < v; j++)
g[i][v] = (g[i][v] - g[i][j] + mo) % mo;
}
}

int tot = path(1,1,n,m);
for (int v = 0; v <= 20; v++) {
ans = (ans + 1LL*s*g[1][v]%mo) % mo;
s = (s&1)?(s>>1)+1:s>>1;
tot -= g[1][v];
tot = (tot + mo) % mo;
}
ans = (ans + 1LL*s*tot%mo) % mo;
ans = 1LL*ans*ksm(path(1,1,n,m),mo-2)%mo;
cout << ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐