Noip2018 填数游戏
不妨设 \(n\le m\)。
首先得发现一些信息:
-
每一个 左下 - 右上 对角线单调不增。
-
如果不成立,一定能找得到两条不满足描述的路径,满足这两条路径只有两个时刻位置不一样:
形如:( \(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\),于是这题可以做到更优秀的复杂度。