AGC 018E.Sightseeing Plan(組合 DP)

題目連接git

\(Description\)

給定三個不相交的矩形\(A(X1,Y1)-(X2,Y2),B(X3,Y3)-(X4,Y4),C(X5,Y5)-(X6,Y6)\),求 從第一個矩形中某點\(a\)出發,通過第二個矩形中的某點\(b\),到達第三個矩形中某點\(c\) 的路徑數。\(a,b,c\)有一個不一樣則路徑算做不一樣。
\(1\leq X1\leq X2<X3\leq X4<X5\leq X6,1\leq Y1\leq Y2<Y3\leq Y4<Y5\leq Y6\)github

\(Solution\)

這寫的很好啊spa

題目的限制不少,咱們考慮簡化題目。3d

\(C(x,y)\)表示網格圖上從\((0,0)\)走到\((x,y)\)的方案數(不是指組合數)。它能夠用組合數\(O(1)\)計算。
那麼有:\[\sum_{y=0}^YC(X,y)=C(X+1,Y)\]code

(dalao就跳過這吧)
不難理解,大概就是這樣(橫縱座標軸畫反了QAQ仍是不要看這個圖了 畫畫吧。。):

設每條路徑最後離開\(x=X\)時座標爲\((X,y)(0\leq y\leq Y)\),那麼到\(x=X+1\)後就有惟一的一條路徑到達\((X+1,Y)\),因此對應方案數爲\(C(X,y)(0\leq y\leq Y)\)。因此有\(C(X+1,Y)=\sum_{y=1}^YC(X,y)\)blog

擴展到二維狀況,有:\[\sum_{x=0}^X\sum_{y=0}^YC(x,y)=C(X+1,Y+1)-1\]ip

由剛剛的結論,左邊能夠寫成\(\sum_{x=0}^XC(x+1,Y)=\sum_{x=1}^{X+1}C(x,Y)\),就是\(C(X+1,Y+1)-1\)
怎麼獲得的同上,考慮最後離開\(y=Y\)的位置(不放圖了太醜了)。
不過會有\((0,0)\)\((0,Y)\)再到\((X+1,Y+1)\)的路徑(而\(x\neq0\)),由於這條路徑是惟一的因此減一便可。get

用二維差分就能夠將其對應到一個矩形\((X1,Y1)-(X2,Y2)\)上:\[\sum_{x=X1}^{X2}\sum_{y=Y1}^{Y2}C(x,y)=C(X2+1,Y2+1)-C(X2+1,Y1)-C(X1,Y2+1)+C(X1,Y1)\]it

咱們能夠看出,對於統計一個點到某個矩形內的方案數,能夠轉化爲求該點到四個點的方案數。io

對於兩個矩形,咱們能夠\(4\times4\)兩兩枚舉矩形的四個關鍵點,貢獻就是對應方案數乘兩個關鍵點的兩個符號。由於能夠看作求第二個矩形的四個關鍵點到第一個矩形的方案數,即右上到左下,因此第一個矩形是拆成\(C(X2,Y2)-C(X2,Y1-1)-C(X1-1,Y2)+C(X1-1,Y1-1)\)(是這樣理解吧...否則我就不知道爲何這樣了...求指正QAQ)。

對於三個矩形,枚舉一三兩個矩形的兩個關鍵點後,就成了求給定起點、終點,通過第二個矩形的路徑數。
對於每條通過第二個矩形\(len\)個點的路徑,對應\(len\)種方案。將\(len\)拆開,咱們枚舉進入/離開第二個矩形時的橫/縱座標,就能夠算\(len\)了。具體是 \(起點到離開點的距離-起點到進入點的距離+1\)\((0,0)\)\((x,y)\)通過的點數爲\(x+y+1\))(也能夠直接都用\((0,0)\)算到它們的方案不須要用起點\((x1,y1)\))。
固然距離要乘上\(起點到枚舉點的方案數*枚舉點到終點的方案數\)

複雜度\(O(16\max(x,y))\)


改了一下午發現是最底下的g[j]寫成g[i]了???


//862ms 15744KB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define mod 1000000007
#define Add(x,v) (x+=v)>=mod&&(x-=mod)
typedef long long LL;
const int N=2e6;

int fac[N+3],ifac[N+3];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline int FP(int x,int k)
{
    int t=1;
    for(; k; k>>=1,x=1ll*x*x%mod)
        if(k&1) t=1ll*t*x%mod;
    return t;
}
#define C(n,m) (1ll*fac[n+m]*ifac[n]%mod*ifac[m]%mod)//C(n+m,n)
int Calc(int x1,int y1,int sign1,int x2,int y2,int sign2,int X3,int X4,int Y3,int Y4)
{//(x1,y1)->(x2,y2)
    LL res=0;
    for(int x=X3; x<=X4; ++x)
        Add(res,1ll*(x+Y4+1)*C(x-x1,Y4-y1)%mod*C(x2-x,y2-Y4-1/*強制下一步離開y=Y4*/)%mod),
        Add(res,mod-1ll*(x+Y3)*C(x-x1,Y3-y1-1/*強制最後一步是到達y=Y3*/)%mod*C(x2-x,y2-Y3)%mod);
//      Add(res,1ll*(x-x1+Y4-y1+1)*C(x-x1,Y4-y1)%mod*C(x2-x,y2-Y4-1)%mod),
//      Add(res,mod-1ll*(x-x1+Y3-y1)*C(x-x1,Y3-y1-1)%mod*C(x2-x,y2-Y3)%mod);
    for(int y=Y3; y<=Y4; ++y)
        Add(res,1ll*(y+X4+1)*C(y-y1,X4-x1)%mod*C(y2-y,x2-X4-1)%mod),
        Add(res,mod-1ll*(y+X3)*C(y-y1,X3-x1-1)%mod*C(y2-y,x2-X3)%mod);
//      Add(res,1ll*(y-y1+X4-x1+1)*C(y-y1,X4-x1)%mod*C(y2-y,x2-X4-1)%mod),
//      Add(res,mod-1ll*(y-y1+X3-x1)*C(y-y1,X3-x1-1)%mod*C(y2-y,x2-X3)%mod);

    res%=mod;
    return sign1*sign2*res;
}

int main()
{
    fac[0]=fac[1]=1, ifac[N]=407182070;
    for(int i=2; i<=N; ++i) fac[i]=1ll*fac[i-1]*i%mod;
    for(int i=N; i; --i) ifac[i-1]=1ll*ifac[i]*i%mod;

    static int f[4][3],g[4][3];

    int x1=read(),x2=read(),x3=read(),x4=read(),x5=read(),x6=read(),
        y1=read(),y2=read(),y3=read(),y4=read(),y5=read(),y6=read();

    f[0][0]=x1-1, f[0][1]=y1-1, f[0][2]=1;
    f[1][0]=x2, f[1][1]=y1-1, f[1][2]=-1;
    f[2][0]=x1-1, f[2][1]=y2, f[2][2]=-1;
    f[3][0]=x2, f[3][1]=y2, f[3][2]=1;

    g[0][0]=x5, g[0][1]=y5, g[0][2]=1;
    g[1][0]=x6+1, g[1][1]=y5, g[1][2]=-1;
    g[2][0]=x5, g[2][1]=y6+1, g[2][2]=-1;
    g[3][0]=x6+1, g[3][1]=y6+1, g[3][2]=1;

    LL ans=0;
    for(int i=0; i<4; ++i)
        for(int j=0; j<4; ++j)
            ans+=Calc(f[i][0],f[i][1],f[i][2],g[j][0],g[j][1],g[j][2],x3,x4,y3,y4);
    printf("%lld\n",(ans%mod+mod)%mod);

    return 0;
}
相關文章
相關標籤/搜索