zoukankan      html  css  js  c++  java
  • AT1761 square1001の通学経路 (square1001's School Road)

    AT1761 square1001の通学経路 (square1001's School Road)

    ATcoder
    Luogu

    問題文
    square1001は、毎日歩いて中学校まで通っている。

    彼は、左下の交差点 (1,1) に住んでおり、 右上の交差点 (W,H)にある学校まで行く。

    ただし、次のような条件がある。

    彼は時間短縮のために右か上にしか進まない。
    彼はその日、K 個のマスに用事があった。
    左下 が(Xi,Yi) で, 右上が(Xi+1,Yi+1) のマスである。
    そのため、用事のあるマスそれぞれについて、その周りの交差点4つのうち少なくとも1つは通る必要があった。

    それらの条件を満たす行き方は何通りあるか。 mod 1,000,000,007で求めよ。
    入力例1

    4 4 1
    2 2
    

    出力例1

    18
    


    (1,1)→(1,2)→(1,3)→(1,4)→(2,4)→(3,4)→(4,4)という行き方と、

    (1,1)→(2,1)→(3,1)→(4,1)→(4,2)→(4,3)→(4,4)という行き方はできない。

    よって, 20−2=18を出力する。

    ※図の左上数が抜けていてすみません。

    题意翻译

    square1001每天步行到学校。

    他住在左下方的十字路口(1,1),去位于右上角(W,H)的学校。

    但是,有一些条件。

    他为了缩短时间只能往右或上走。 那天,他找了有K个格子,左下角坐标分别为(Xi1,Yi1),(Xi2,Yi2),(Xi3,Yi3) ......(XiK,YiK)

    而且,对于这种的格子,其周围的4个格子(指周围四个格子中四个顶点坐标中的一个)中square1001至少需要经过1个。

    满足这些条件的路径有多少条?

    答案mod 1,000,000,007后输出 。

    怎么做呢?

    这种题直接考虑DP计数就好了。
    有一个比较类似的题建议做一下。
    CF559C Gerald and Giant Chess
    这道题的转移:对于每一个点,可以直接由它的左下加右下转移过来。至于限制条件怎么走,我们发现对于每一个方块,必行的两个点的横坐标加纵坐标是一定的,因此可以维护一个数组,当且仅当它与地图上记录的点的信息对应时进行转移。

    //记录点的信息
    ++mp[x + 1][y];++mp[x][y + 1];
    //对每个横纵坐标的合维护出现次数
    ++cnt[x + y + 1];
    //转移时进行判断
    cnt[i + j] == mp[i][j]
    

    拿样例进行说明,例如在(1,4)点时(是非法状态不能转移),由于cnt[5] = 1,mp[1][4] = 0,不能进行转移。由此保证路径一定经过必过的点。
    这个是我看了snow39的代码发现的好技巧。

    代码

    #include <bits/stdc++.h>
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    #ifdef lky233
    #define nextchar getchar
    #endif
    template <typename Y>
    inline void poread(Y &ret)
    {
        ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
    }
    #undef nextcar
    } // namespace fdata
    using fdata::poread;
    using namespace std;
    const int MAXN = 1005;
    const int MOD = 1e9 + 7;
    int f[MAXN][MAXN];
    int mp[MAXN][MAXN];
    int cnt[MAXN];
    int h, w, k;
    int main()
    {
        poread(h), poread(w), poread(k);
        for (register int i = 1, x, y; i <= k; ++i)
        {
            poread(x), poread(y);
            ++mp[x + 1][y];
            ++mp[x][y + 1];
            ++cnt[x + y + 1];
        }
        f[1][1] = 1;
        for (register int i = 1; i <= h; ++i)
        {
            for (register int j = 1; j <= w; ++j)
            {
                if (i != 1 && cnt[i + j] == mp[i][j])
                    f[i][j] = (f[i][j] + f[i - 1][j]) % MOD;
                if (j != 1 && cnt[i + j] == mp[i][j])
                    f[i][j] = (f[i][j] + f[i][j - 1]) % MOD;
            }
        }
        cout << f[h][w] << endl;
    }
    

    我在看的时候看到了一份python代码,于是搬过来了。
    来源提交记录

    from collections import defaultdict,deque
    import sys,heapq,bisect,math,itertools,string,queue,datetime,random
    sys.setrecursionlimit(10**8)
    INF = float('inf')
    mod = 10**9+7
    eps = 10**-7
    def inpl(): return list(map(int, input().split()))
    def inpls(): return list(input().split())
     
    H,W,K = inpl()
    XYs = [inpl() for _ in range(K)]
    XYs.sort()
     
    MAX = H+W
    fac = [1]*(MAX+1)
    for i in range(1,MAX+1):
    	fac[i] = (fac[i-1]*i)%mod
     
    gyakugen = [1]*(MAX+1)
    gyakugen[MAX] = pow(fac[MAX],mod-2,mod)
    for i in range(MAX,0,-1):
    	gyakugen[i-1] = (gyakugen[i]*i)%mod
     
    def Comb (n,k):#nCk
    	return (fac[n]*gyakugen[k]*gyakugen[n-k])%mod
     
    def calc(xys,xyt):
        dx = xyt[0] - xys[0]
        dy = xyt[1] - xys[1]
        return Comb(dx+dy,dx)
     
    def LU(xy):
        x,y = xy
        return([x,y+1])
     
    def RD(xy):
        x,y = xy
        return([x+1,y])
     
    tmp0 = calc([1,1],LU(XYs[0]))
    tmp1 = calc([1,1],RD(XYs[0]))
    for i in range(1,K):
        tmp0ed,tmp1ed = tmp0,tmp1
        tmp0 = tmp0ed * calc(LU(XYs[i-1]),LU(XYs[i])) + tmp1ed * calc(RD(XYs[i-1]),LU(XYs[i]))
        tmp1 = tmp0ed * calc(LU(XYs[i-1]),RD(XYs[i])) + tmp1ed * calc(RD(XYs[i-1]),RD(XYs[i]))
        tmp0 %= mod
        tmp1 %= mod
     
    ans = tmp0 * calc(LU(XYs[K-1]),[W,H]) + tmp1 * calc(RD(XYs[K-1]),[W,H])
    print(ans%mod)
    
  • 相关阅读:
    HUST 1372 marshmallow
    HUST 1371 Emergency relief
    CodeForces 629D Babaei and Birthday Cake
    CodeForces 629C Famil Door and Brackets
    ZOJ 3872 Beauty of Array
    ZOJ 3870 Team Formation
    HDU 5631 Rikka with Graph
    HDU 5630 Rikka with Chess
    CodeForces 626D Jerry's Protest
    【POJ 1964】 City Game
  • 原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11593336.html
Copyright © 2011-2022 走看看