1. 程式人生 > >流浪者(rover)

流浪者(rover)

流浪者(rover)

題目描述

 

有一位流浪者正在一個n∗mn∗m的網格圖上流浪。初始時流浪者擁有SS點體力值。

流浪者會從(1,1)(1,1)走向(n,m)(n,m),並且他只會向下走((x,y)→(x+1,y))((x,y)→(x+1,y))或是往右走((x,y)→(x,y+1))((x,y)→(x,y+1)),在所有可行的路線中他會隨機選擇一條。

網路圖中還有KK個障礙點。若流浪者當前體力值為SS,則他經過一個障礙點後體力值會變為⌈S2⌉⌈S2⌉。

現在請你求出,流浪者到達(n,mn,m)時他體力值的期望是多少。

 

若答案為abab,則你輸出abab在模109+7109+7意義下的值即可。

 

 

輸入

 

第一行四個整數n,m,K,Sn,m,K,S, 意義見題目描述。

接下來K行每行兩個整數Xi,YiXi,Yi,表示一個障礙點,保證一個障礙點不會出現多次。起點與終點可能也會是障礙點。

 

 

輸出

 

僅一行一個整數表示答案。

 

 

樣例1解釋

共有6種合法路徑,這裡不一一列出。

16∗(6+6+11+3+6+6)=19316∗(6+6+11+3+6+6)=193

約定

30%的資料:n,m≤10n,m≤10

50%的資料:n,m≤1000n,m≤1000

 

1000%的資料:1≤n,m≤105,0≤K≤min(n∗m,2000),1≤S≤1061≤n,m≤105,0≤K≤min(n∗m,2000),1≤S≤106

 


solution

slz:經典模型

我:完全不會

30:dfs

50:dp 令f[i][j][k]表示走到i j,經過k個格子的方案數

由於當k>20時對k不同對答案沒有影響,最後一維可以只開20

O(nm20)

100:

dp 令f[i][j]表示當前在第i個特殊點,走到終點還會經過恰好j個特殊點的路徑數

g[i][j]表示當前在第i個特殊點,走到終點還會經過小於等於j個特殊點的路徑數

f[i][j]=g[i][j]-g[i][j-1]

g[i][j]=ways(i,n)-ways(i,k)*f[i][k]

ways(i,j)表示i到j的路徑數

從後往前dp即可

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define maxn 2005
#define mod 1000000007
#define ll long long
using namespace std;
int n,m,K,S,s[24];
ll h[200008],ny[200008],f[maxn][25],g[maxn][23];
ll work(ll a,int num){
    ll ans=1;
    while(num){
        if(num&1)ans=ans*a;
        a=a*a;a%=mod;ans%=mod;num>>=1;
    }
    return ans;
}
struct node{
    int x,y;
}p[maxn];
bool cmp(node a,node b){
    return a.x<b.x||a.x==b.x&&a.y<b.y;
}
ll C(int N,int M){
    return h[N]*ny[M]%mod*ny[N-M]%mod;
}
int main()
{
    cin>>n>>m>>K>>S;
    int Max=200005;h[0]=1;
     
    for(int i=1;i<=Max;i++)h[i]=h[i-1]*i%mod;
    ny[Max]=work(h[Max],mod-2);
    for(int i=Max-1;i>=0;i--)ny[i]=ny[i+1]*(i+1)%mod;
    s[0]=S;int cnt=0;
    for(;s[cnt]>1;cnt++)s[cnt+1]=(s[cnt]+1)/2;
    for(int i=1;i<=K;i++){
        scanf("%d%d",&p[i].x,&p[i].y);
    }
    sort(p+1,p+K+1,cmp);
    p[0].x=1;p[0].y=1;
    for(int i=K;i>=0;i--){
        int xi=p[i].x,yi=p[i].y;
        for(int j=0;j<cnt;j++){
            ll sum=0;g[i][j]=C(n-xi+m-yi,n-xi);
            for(int k=K;k>i;k--){
                if(p[k].y<p[i].y)continue;
                int xk=p[k].x,yk=p[k].y;
                sum+=f[k][j]*C(xk-xi+yk-yi,xk-xi)%mod;
                sum%=mod;
            }
            g[i][j]-=sum;g[i][j]%=mod;
        }
        g[i][cnt]=C(n-xi+m-yi,n-xi);
        for(int j=1;j<=cnt;j++)f[i][j]=(g[i][j]-g[i][j-1])%mod;
        f[i][0]=g[i][0]; 
    }
    ll Answer=0;
    for(int i=0;i<=cnt;i++){
        Answer+=f[0][i]*s[i]%mod;
        Answer%=mod;
    }
    ll All=C(n+m-2,m-1);
    Answer=Answer*work(All,mod-2);
    Answer=(Answer%mod+mod)%mod;
    printf("%lld\n",Answer);
    return 0;
}