Noip2018 填数游戏

不妨设 \(n\le m\)。

首先得发现一些信息:

  1. 每一个 左下 - 右上 对角线单调不增。

  2. 如果不成立,一定能找得到两条不满足描述的路径,满足这两条路径只有两个时刻位置不一样:
    形如:( \(c\) 表示 \(ab\) 都经过的点)
    \[ \begin{matrix} c & c & a & & \\ & b & c & c & c \\ & & & b & c \end{matrix} \]

仔细分析我们可以找到如下结论:

若有以下形状:
\[ \begin{matrix} & 1 \\ 1 & x \end{matrix} \]
则位置 \(x\) 右下角(包括 \(x\) )的矩形中,每个 左下 - 右上 对角线在这一段都一样。

结合以上的小结论不难发现这是充要条件。

如果讨论出公式的话不太现实,这里给出一个较为轻松的讨论方式。

考虑前三个对角线怎么选择,分类讨论:

Case 1

? 1   |   ? 0
1     |   0

这个很好讨论,因为不会在其它位置出现限制了。

Case 2

? 0 1/0
1 1/0
1/0

同上,也很好讨论,多判断第四行即可。

Case 3

? 0 0 _ _
1 1 _ _ _
1 x x x x
_ x x x x
_ x x x x

这个情况需要再讨论一下上方出现相同的情况。

? 0 0 1 _
1 1 1 _ _
1 x x x x
_ x x x x
_ x x x x

这类情况。

枚举在在第几个出现相同的情况,讨论计算即可。

注意的是需要注意 \(n\ne m​\) 的时候的一些特判。

Case 4

? 0 0 _ _ 
1 0 x x x 
1 _ x x x 
_ _ x x x 
_ _ x x x 

同上,但是与之上的代码在细节上有些差别。

写出来已经可以通过。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline int mul(int a,int b,int c){return mul(a,mul(b,c));}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
/* math */
int n,m;

int main()
{
    cin >> n >> m;
    if(n>m)swap(n,m);
    if(n<=3){
        if(n==1){
            cout << qpow(2,m) << endl;
        }else if(n==2){
            cout << 12ll*qpow(3,m-2)%mod << endl;
        }else if(n==3){
            cout << 112ll*qpow(3,m-3)%mod << endl;
        }
        return 0;
    }
    /* 
    ? 1 | ? 0
    1   | 0
     */
    int w1 = 2ll*mul(qpow(4,n-2),qpow(3,m-n),qpow(2,n-1))%mod;
    /* 
    ? 0 1/0
    1 1/0
    1/0
     */
    int w2 = 2ll*5ll*mul(qpow(4,n-4),qpow(3,m-n),qpow(2,n-1))%mod;
    /*
    ? 0 0 _ _
    1 1 _ _ _
    1 x x x
    _ x x x
    _
    */
    int g3 = qpow(2,n-2), w3 = 3ll*g3%mod;
    for(int i=4;i<m;i++){
        int ths = 0;
        if(i<=n)ths = 4;
        else ths = 3;
        int d = i+1;
        if(d <= n)ths *= 5;
        else ths *= 4;
        int nxt1 = max(0,n-d),nxt2 = m-d-nxt1;
        w3 = add(w3, mul(mul(2ll*g3%mod,ths),qpow(4,nxt1),qpow(3,nxt2)));
    }
    w3 = add(w3, mul ( m <= n ? 4 : 3, 3ll*g3%mod));
    /*
    ? 0 0 _ _ 
    1 0 x x x 
    1 _ x x x 
    _ _ x x x 
    _ _ x x x 
    */
    int _t = min(m-2,n-1), _t2 = m-2-_t;
    int g4 = mul(qpow(2,_t), qpow(3,_t2));
    int w4 = (n<m?4ll:3ll)*g4%mod, __w = w4;
    w4 = add(w4, mul( 4 , __w));
    for(int i=4;i<n;i++){
        int ths = 4;
        ths *= 5;
        w4 = add(w4, mul((n<m?3ll:2ll)*g4%mod, ths, qpow(4, n-i-1)));
    }
    // cout << w3 << " " << w4 << endl;
    /*  */
    int ans = add(add(w1,w2),add(w3,w4));
    ans = mul(ans,2);
    cout << ans << endl;
}

仔细分析会发现还有一些性质:

\(n\)固定的时候,\(m + 1\) 后每个位置上的贡献都会多乘 \(3\),于是这题可以做到更优秀的复杂度。

上一篇:题解【NOIP2018提高组D2T3 保卫王国】


下一篇:NOIP2018 游记