题意
T
T
T组数据,每组数据给你三个正整数
n
,
m
,
k
n,m,k
n,m,k,其中
n
,
m
n,m
n,m分别为积木的长和宽(积木由若干个
1
×
1
×
1
1\times1\times1
1×1×1的小方块组成),再给你左前视图(如图所示)每一部分的最终高度
a
i
a_i
ai(共
n
+
m
n+m
n+m部分),接下来
k
k
k行,每行三个正整数
x
,
y
,
h
x,y,h
x,y,h,表示第
x
x
x行
y
y
y列的高度指定为正整数
h
h
h,问你合法的积木总数,对
1
0
9
+
7
10^9+7
109+7取模。
数据范围:
1
⩽
T
,
n
,
m
,
k
⩽
1
0
5
,
1
⩽
a
i
,
h
i
⩽
1
0
9
1\leqslant T,n,m,k\leqslant 10^5,1\leqslant a_i,h_i\leqslant 10^9
1⩽T,n,m,k⩽105,1⩽ai,hi⩽109
1
⩽
x
i
⩽
n
,
1
⩽
y
i
⩽
m
,
∑
n
,
∑
m
,
∑
k
⩽
1
0
5
1\leqslant x_i\leqslant n,1\leqslant y_i\leqslant m,\sum_{}n,\sum_{} m,\sum_{} k\leqslant 10^5
1⩽xi⩽n,1⩽yi⩽m,∑n,∑m,∑k⩽105
思路
①我们设
l
i
m
i
,
c
n
t
i
,
p
i
lim_i,cnt_i,p_i
limi,cnti,pi分别为左前视图第
i
i
i部分的 高度(即
a
i
a_i
ai)、还剩多少个没指定高度的方块、通过已经指定的方块达到的高度。
注意:左前视图第
i
i
i部分的高度只会受到指定方块
(
x
,
y
)
(x,y)
(x,y)(
x
+
y
=
i
或
者
x
+
y
=
i
+
1
x+y=i或者x+y=i+1
x+y=i或者x+y=i+1)的高度的影响。
②显然有两种不合法的情况(即答案为0):
c
n
t
i
<
0
cnt_i<0
cnti<0或者
p
i
>
l
i
m
i
p_i>lim_i
pi>limi
③设
d
p
[
i
]
[
0
/
1
]
dp[i][0/1]
dp[i][0/1]分别表示左前视图第
i
i
i部分的高度 没有/有 达到最终高度的合法的方案总数。
设函数
c
a
l
(
x
,
n
)
cal(x,n)
cal(x,n)表示
n
n
n个位置每个位置有
1
,
2
,
.
.
.
,
x
1,2,...,x
1,2,...,x共
x
x
x种高度可以选择,并且高度
x
x
x一定被选择的方案总数。
设函数
p
o
w
e
r
(
x
,
n
)
power(x,n)
power(x,n)表示
n
n
n个位置每个位置有
1
,
2
,
.
.
.
,
x
1,2,...,x
1,2,...,x共
x
x
x种高度可以选择的方案总数。
因此可以分两种情况转移(为了表述更清晰,以下状态转移的时候忽略取模操作):
令
a
=
l
i
m
i
−
1
,
b
=
l
i
m
i
a=lim_{i-1},b=lim_i
a=limi−1,b=limi
1
、
p
i
<
l
i
m
i
1、p_i<lim_i
1、pi<limi
d
p
[
i
]
[
1
]
+
=
d
p
[
i
−
1
]
[
1
]
×
c
a
l
(
b
,
c
n
t
i
)
,
(
a
⩾
b
)
dp[i][1]+=dp[i-1][1]\times cal(b,cnt_i),(a \geqslant b)
dp[i][1]+=dp[i−1][1]×cal(b,cnti),(a⩾b)
d
p
[
i
]
[
1
]
+
=
d
p
[
i
−
1
]
[
0
]
×
c
a
l
(
a
,
c
n
t
i
)
,
(
a
=
=
b
)
dp[i][1]+=dp[i-1][0]\times cal(a,cnt_i),(a==b)
dp[i][1]+=dp[i−1][0]×cal(a,cnti),(a==b)
d
p
[
i
]
[
0
]
+
=
d
p
[
i
−
1
]
[
1
]
×
p
o
w
e
r
(
m
i
n
(
a
,
b
−
1
)
,
c
n
t
i
)
dp[i][0]+=dp[i-1][1]\times power(min(a,b-1),cnt_i)
dp[i][0]+=dp[i−1][1]×power(min(a,b−1),cnti)
d
p
[
i
]
[
0
]
+
=
d
p
[
i
−
1
]
[
0
]
×
c
a
l
(
a
,
c
n
t
i
)
,
(
a
<
b
)
dp[i][0]+=dp[i-1][0]\times cal(a,cnt_i),(a<b)
dp[i][0]+=dp[i−1][0]×cal(a,cnti),(a<b)
2
、
p
i
=
=
l
i
m
i
2、p_i==lim_i
2、pi==limi
d
p
[
i
]
[
1
]
+
=
d
p
[
i
−
1
]
[
1
]
×
p
o
w
e
r
(
m
i
n
(
a
,
b
)
,
c
n
t
i
)
dp[i][1]+=dp[i-1][1]\times power(min(a,b),cnt_i)
dp[i][1]+=dp[i−1][1]×power(min(a,b),cnti) (这个式子一定要仔细思考)
d
p
[
i
]
[
1
]
+
=
d
p
[
i
−
1
]
[
0
]
×
c
a
l
(
a
,
c
n
t
i
)
,
(
a
⩽
b
)
dp[i][1]+=dp[i-1][0]\times cal(a,cnt_i),(a\leqslant b)
dp[i][1]+=dp[i−1][0]×cal(a,cnti),(a⩽b)
d
p
[
i
]
[
0
]
=
0
dp[i][0]=0
dp[i][0]=0
④时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),注意初始化和取模。
PS:看似只有简单的几个转移方程,实际上要每种情况都思考的非常清楚,不能有任何偏差,这正是这道题目的难度所在。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define VV vector<int>
#define PP pair<int,int>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef long long ll;
template <typename T>
inline void read(T &X){
X=0;int w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
if(w) X=-X;
}
const int maxn=4e5+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
const ll mo=1e9+7;
ll n,m,k;
ll a[maxn],c[maxn];
ll ans;
ll p[maxn], lim[maxn], cnt[maxn];
ll dp[maxn][2];
ll power(ll a,ll n){
ll sum = 1;
while(n){
if(n&1)
sum = sum * a % mo;
n >>= 1;
a = a * a % mo;
}
return sum;
}
ll cal(ll a, ll n) { return (power(a, n) - power(a - 1, n) + mo) % mo; }
void solve(){
read(n);read(m);read(k);
int len = n + m;
rep(i, 0, len) p[i] = lim[i] = cnt[i] = 0;
rep(i,1,len){
read(lim[i]);
cnt[i + 1] = min(min(n, m), min(1LL * i, n + m - i));
}
rep(i,1,k){
int x, y, h;
read(x);
read(y);
read(h);
p[x + y] = max(p[x + y], 1LL * h);
p[x + y - 1] = max(p[x + y - 1], 1LL * h);
cnt[x + y]--;
}
rep(i,1,len) if(cnt[i]<0||p[i]>lim[i]){
puts("0");
return;
}
dp[1][1] = 1;
dp[1][0] = 1;
if(p[1]==lim[1])
dp[1][0] = 0;
else
dp[1][1] = 0;//
rep(i,2,len){
dp[i][0] = dp[i][1] = 0;
ll a = lim[i - 1], b = lim[i];
if(p[i]<lim[i]){
if(a>=b)//?
dp[i][1] = (dp[i][1] + dp[i - 1][1] * cal(b, cnt[i]) % mo) % mo;//
if(a==b)//
dp[i][1] = (dp[i][1] + dp[i - 1][0] * cal(a, cnt[i]) % mo) % mo;//
if(a<b)//
dp[i][0] = (dp[i][0] + dp[i - 1][0] * cal(a, cnt[i]) % mo) % mo;//
dp[i][0] = (dp[i][0] + dp[i - 1][1] * power(min(a, b - 1), cnt[i]) % mo) % mo;
}
else {
dp[i][1] = (dp[i][1] + dp[i - 1][1] * power(min(a, b), cnt[i]) % mo) % mo;//?
if(a<=b)//
dp[i][1] = (dp[i][1] + dp[i - 1][0] * cal(a, cnt[i]) % mo) % mo;//
dp[i][0] = 0;
}
}
printf("%lld\n", dp[len][1]);
}
int main(){
//freopen("e://duipai//data.txt","r",stdin);
//freopen("e://duipai//amyout.txt","w",stdout);
int T=1,cas=1;
read(T);
while(T--){
printf("Case #%d: ", cas++);
solve();
}
//system("pause");
return 0;
}