题意:
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 取模。
我们设
c
n
t
i
cnt_i
cnti 为
i
i
i 与
i
+
1
i+1
i+1间夹的部分,高度随意的木块儿的数量,
p
i
p_i
pi 为固定的第
i
i
i 部分木块儿的最大高度。
函数
c
a
l
(
h
,
c
n
t
)
cal(h,cnt)
cal(h,cnt) 表示搭 cnt 个木块儿,最高高度为 h,且至少有一个达到 h 的方案数。
p
o
w
e
r
(
h
,
c
n
t
)
power(h, cnt)
power(h,cnt) 表示搭 cnt 个木块儿,最高高度为 h,可以没有木块儿达到 h。
f
(
i
,
0
/
1
)
f(i, 0/1)
f(i,0/1) 表示第 i 个部分,0 没有到达最大高度,1 达到最大高度。而这个部分的与
a
i
a_i
ai 和
a
i
−
1
a_{i-1}
ai−1 的限制有关。
有一个地方容易想错,就是说,n个位置,至少有一个高度为h(每个位置最小高度为1),求方案数。可以这样考虑,选择
k
k
k 个位置高度到
h
h
h,那么
n
−
k
n-k
n−k 个位置最多到
h
−
1
h-1
h−1,那么方案数为
∑
k
=
1
n
C
n
k
(
h
−
1
)
n
−
k
=
∑
k
=
n
C
n
k
(
h
−
1
)
n
−
k
−
(
h
−
1
)
n
=
k
n
−
(
k
−
1
)
n
\sum\limits_{k=1}^nC_{n}^{k}(h-1)^{n-k} = \sum\limits_{k=}^nC_{n}^{k}(h-1)^{n-k}-(h-1)^n = k^n-(k-1)^n
k=1∑nCnk(h−1)n−k=k=∑nCnk(h−1)n−k−(h−1)n=kn−(k−1)n. 这样子的话,样例1就讲通了。 题解
#include<iostream>#include<cstring>#include<algorithm>usingnamespace std;constint maxn =200010;typedeflonglong ll;const ll mod =1e9+7;int kase, len, N, M, K;
ll f[maxn][2], p[maxn], a[maxn], cnt[maxn];
ll power(ll h, ll cnt){
ll res =1;while(cnt){if(cnt &1) res = res * h % mod;
h = h * h % mod;
cnt >>=1;}return res;}
ll cal(ll h, ll cnt){return(power(h, cnt)-power(h -1, cnt)+ mod)% mod;}
ll solve(){scanf("%d%d%d",&N,&M,&K);
len = N + M;for(int i =0; i <= len; i++) f[i][0]= f[i][1]= p[i]= a[i]= cnt[i]=0;for(int i =1; i <= len; i++){scanf("%lld",&a[i]);
cnt[i +1]=min(min(N, M),min(i, N + M - i));}for(int i =1; i <= K; i++){int x, y, h;scanf("%d%d%d",&x,&y,&h);
p[x + y]=max(p[x + y],(ll)h);
p[x + y -1]=max(p[x + y -1],(ll)h);
cnt[x + y]--;}//for (int i = 1; i <= len; i++) printf("%lld ", cnt[i]);
f[1][0]= f[1][1]=1;if(a[1]== p[1]) f[1][0]=0;else f[1][1]=0;for(int i =2; i <= len; i++){//这个是循环每一斜对角线的方块儿if(p[i]> a[i])return0;if(p[i]< a[i]){if(a[i -1]>= a[i]){
f[i][1]=(f[i][1]+ f[i -1][1]*cal(a[i], cnt[i])% mod)% mod;}if(a[i -1]== a[i]){
f[i][1]=(f[i][1]+ f[i -1][0]*cal(a[i], cnt[i])% mod)% mod;}
f[i][0]=(f[i][0]+ f[i -1][1]*power(min(a[i -1], a[i]-1), cnt[i])% mod)% mod;if(a[i -1]< a[i]){
f[i][0]=(f[i][0]+ f[i -1][0]*cal(a[i -1], cnt[i])% mod)% mod;}}if(p[i]== a[i]){
f[i][1]=(f[i][1]+ f[i -1][1]*power(min(a[i -1], a[i]), cnt[i])% mod)% mod;if(a[i -1]<= a[i]){
f[i][1]=(f[i][1]+ f[i -1][0]*cal(a[i -1], cnt[i])% mod)% mod;}
f[i][0]=0;}}return f[len][1];}intmain(){int T;scanf("%d",&T);while(T--){printf("Case #%d: %lld\n",++kase,solve());}return0;}
B. Code a Trie
Trie+LCA
C. Escape from the Island
图论+dp
D. Fracture Ray
树套树
E. Game of Cards
博弈:你有
c
0
c_0
c0 张值为0的卡,
c
1
c_1
c1 张值为1的卡,
c
2
c_2
c2 张值为2的卡,
c
3
c_3
c3 张值为3的卡,每次操作你可以选取俩张和小于等于3的卡,让他们融合为一张卡,融合的卡的值为他们俩张卡的和,rabbit先手,不能操作的人输。
三种必输态:
c
0
=
0
,
c
1
=
0
c_0 = 0, c_1 = 0
c0=0,c1=0.
c
0
=
1
,
c
2
,
c
3
,
c
4
=
0
c_0=1, c_2, c_3, c_4 = 0
c0=1,c2,c3,c4=0.
c
0
=
0
,
c
1
=
1
,
c
2
=
0
c_0 = 0, c_1 = 1, c_2 = 0
c0=0,c1=1,c2=0.
有三种变化
c
0
,
c
1
−
1
,
c
2
,
c
3
c_0, c_1-1, c_2, c_3
c0,c1−1,c2,c3
c
0
,
c
1
−
1
,
c
2
−
1
,
c
3
+
1
c_0, c_1 - 1, c_2 - 1, c_3 + 1
c0,c1−1,c2−1,c3+1.
c
0
,
c
1
−
2
,
c
2
+
1
,
c
3
c_0, c_1 - 2, c_2 + 1, c_3
c0,c1−2,c2+1,c3
接着我们发现,只要
c
2
≥
1
c_2 \ge 1
c2≥1,无论先手如何,后手都可以让
c
0
c_0
c0 减 2 或者
c
1
c_1
c1 减3. 因此,
c
2
=
0
c_2 = 0
c2=0 需要特判,其他的直接深搜就行。
2021 BNU Winter Training 9 (2020 China Collegiate Programming Contest - Mianyang Site)训练网址A. Building Blocks题意:TTT组数据,每组数据给你三个正整数n,m,kn,m,kn,m,k,其中n,mn,mn,m分别为积木的长和宽(积木由若干个1×1×11\times1\times11×1×1的小方块组成),再给你左前视图(如图所示)每一部分的最终高度aia_iai(共n+mn+mn+m部分),接