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

3130: 流浪者(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,表示一個障礙點,保證一個障礙點不會出現多次。起點與終點可能也會是障礙點。

輸出

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

樣例輸入

<span style="color:#333333"><span style="color:#333333">樣例1輸入
3 3 2 11
2 1
2 3
樣例2輸入
1 6 2 15
1 1
1 5</span></span>

樣例輸出

<span style="color:#333333"><span style="color:#333333">樣例1輸出
333333342
樣例2輸出
4</span></span>

提示

樣例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

來源

題解:

dp,f[i][j]表示從第i個特殊點出發經歷正好j個特殊點到達(n,m)的方案數,可是這個dp不好轉移。

所以我們再用g[i][j]表示至多走過j個點的方案數,這樣f[i][j]=g[i][j]-g[i][j-1]。

那麼g[i[][j]也很好轉移,列舉下一個經過的特殊點即可轉移。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define mod 1000000007
using namespace std;
int n,m,k,S,cnt,b[200005];long long jc[200005],ny[200005],g[2005][30],ans;
struct Node{int x,y;}s[2005];
bool cmp(Node t1,Node t2){return t1.x<t2.x||(t1.x==t2.x&&t1.y<t2.y);}
long long ksm(long long x,long long y)
{
    long long sum=1;
    while(y)
    {
        if(y&1)sum=sum*x%mod;
        x=x*x%mod;y>>=1;
    }
    return sum;
}
long long C(int x,int y){return jc[x]*ny[y]%mod*ny[x-y]%mod;}
int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&S);
    for(int i=1;i<=k;++i)scanf("%d%d",&s[i].x,&s[i].y);
    sort(s+1,s+1+k,cmp);
    jc[0]=1;
    for(int i=1;i<=2e5;++i)jc[i]=jc[i-1]*i%mod;
    ny[200000]=ksm(jc[200000],mod-2);
    for(int i=2e5;i;--i)ny[i-1]=ny[i]*i%mod;
    b[0]=S;
    while(S!=1)b[++cnt]=(S+1)/2,S=(S+1)/2;
    s[0].x=1;s[0].y=1;
     
    for(int i=k;~i;--i)
    {
        for(int j=0;j<cnt;++j)
        {
            g[i][j]=C(n-s[i].x+m-s[i].y,n-s[i].x);
            for(int t=k;t>i;--t)
                if(s[i].y<=s[t].y)
                    g[i][j]=((g[i][j]-g[t][j]*C(s[t].x-s[i].x+s[t].y-s[i].y,s[t].x-s[i].x)%mod)%mod+mod)%mod;
        }
        g[i][cnt]=C(n-s[i].x+m-s[i].y,n-s[i].x);
        for(int j=cnt;j;--j)g[i][j]=((g[i][j]-g[i][j-1])%mod+mod)%mod;
    }
    for(int i=0;i<=cnt;++i)ans=(ans+g[0][i]*(long long)b[i]%mod)%mod;
    ans=ans*ksm(C(n+m-2,n-1),mod-2)%mod;
    cout<<ans;
}