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)
    
  • 相关阅读:
    计算机基础知识
    看 C++ Primer 的58页, 讲拷贝时不能忽略 底层const这里的说的原因有点牵强, 这里给出自己的理解
    GitHub
    让 typora和word一样好用
    推荐几款好用的文本编辑器,让您的办公更方便快捷。
    UML类图几种关系的总结
    poll, ppoll
    信号之sigaction函数
    posix多线程有感--自旋锁
    Linux IPC
  • 原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11593336.html
Copyright © 2011-2022 走看看