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

posted @ 2019-10-24 21:53  jerome_wei  阅读(364)  评论(0编辑  收藏  举报