• Noip2018 填数游戏


    不妨设 (nle m)

    首先得发现一些信息:

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

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

      [egin{matrix} c & c & a & & \ & b & c & c & c \ & & & b & c end{matrix} ]

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

    若有以下形状:

    [egin{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 e 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),于是这题可以做到更优秀的复杂度。

  • 相关阅读:
    java ssh整合报错:java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I
    Ubuntu16.04安装搜狗输入法后有黑边问题的解决方法
    socket
    vim编辑器的使用
    linux用户和群组
    bash shell
    [LightOJ 1128]Greatest Parent
    [Luogu P4180][BJWC 2010]严格次小生成树
    函数、方法区别
    有关_meta内容(持续更新)
  • 原文地址:https://www.cnblogs.com/weiyanpeng/p/11735209.html
Copyright © 2020-2023  润新知