题意
给定一个
n
×
m
n \times m
n×m的网格,每个网格都放置一张牌。每次选定一个矩形框,然后将这个矩形框内所有牌都反转。问:最多反转两次,可以产生多少种情况。
链接:link。
思路
题目要求翻转次数不超过两次:
翻转次数 | 情况总数 |
---|---|
0 | 1 |
1 | ( n + 1 2 ) ( m + 1 2 ) \binom{n+1}{2} \binom{m+1}{2} (2n+1)(2m+1) |
2 | ( n + 1 2 ) ( m + 1 2 ) ( ( n + 1 2 ) ( m + 1 2 ) − 1 ) 2 \frac{\binom{n+1}{2} \binom{m+1}{2}(\binom{n+1}{2} \binom{m+1}{2}-1)}{2} 2(2n+1)(2m+1)((2n+1)(2m+1)−1) |
用阴影部分表示最终被翻转的区域,以下几种情况会发生计数重复:
翻
1
1
1次和翻
2
2
2次都能得到这种情况,这时要减去所有翻
2
2
2次的情况。
翻
2
2
2次的情况总数为
3
×
(
C
n
+
1
2
C
m
+
1
3
+
C
n
+
1
3
C
m
+
1
2
)
=
C
n
+
1
2
C
m
+
1
2
(
n
+
m
−
2
)
3 \times (C_{n+1}^{2} C_{m+1}^{3}+C_{n+1}^{3} C_{m+1}^{2})=C_{n+1}^{2} C_{m+1}^{2} (n+m-2)
3×(Cn+12Cm+13+Cn+13Cm+12)=Cn+12Cm+12(n+m−2)。
包含了
2
2
2种情况(即横向和纵向),且只能通过翻
2
2
2次得到,这时要减去翻
2
2
2次内部重复的情况。这种情况的总数为
C
n
+
1
2
C
m
+
1
4
+
C
n
+
1
4
C
m
+
1
2
C_{n+1}^{2} C_{m+1}^{4}+C_{n+1}^{4} C_{m+1}^{2}
Cn+12Cm+14+Cn+14Cm+12。
对于每一种情况可以由
3
3
3种
2
2
2次翻转方式得到。这时减去
2
2
2次就行了,也就是减去
2
×
(
C
n
+
1
2
C
m
+
1
4
+
C
n
+
1
4
C
m
+
1
2
)
2 \times (C_{n+1}^{2} C_{m+1}^{4}+C_{n+1}^{4} C_{m+1}^{2})
2×(Cn+12Cm+14+Cn+14Cm+12)。
包含了
4
4
4种情况(即未翻转区可以发生在
4
4
4个区域),只能通过翻两次得到,这时也会出现重复计数。这种情况的总数为
4
×
C
n
+
1
3
C
m
+
1
3
4 \times C_{n+1}^{3} C_{m+1}^{3}
4×Cn+13Cm+13。
每一种情况可以
3
3
3种
2
2
2次翻转得到。减去
2
2
2次就行了,也就是减去
8
×
C
n
+
1
3
C
m
+
1
3
8 \times C_{n+1}^{3} C_{m+1}^{3}
8×Cn+13Cm+13。
包含了
2
2
2种情况(互补的2种情况),只能通过翻转两次得到。这种情况的总数为
2
×
C
n
+
1
3
C
m
+
1
3
2 \times C_{n+1}^{3} C_{m+1}^{3}
2×Cn+13Cm+13。
每一种情况可以由
3
3
3种
2
2
2次翻转得到。这时要减去
4
×
C
n
+
1
3
C
m
+
1
3
4 \times C_{n+1}^{3} C_{m+1}^{3}
4×Cn+13Cm+13。
时间复杂的分析
预处理组合数的时间复杂度为 O ( n 2 ) \mathcal{O}(n^{2}) O(n2),假设询问次数为 t t t,而计算结果的时间复杂度为 O ( 1 ) \mathcal{O}(1) O(1),所以总的时间复杂度为 O ( n 2 + t ) \mathcal{O}(n^{2}+t) O(n2+t)。
实现
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=105;
ll n,m,c[N][N];
char s[N];
int main(){
for(int i=0;i<N;i++) c[i][0]=c[i][i]=1;
for(int i=0;i<N;i++){
for(int j=1;j<i;j++){
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
}
while(~scanf("%lld%lld",&n,&m)){
for(int i=0;i<n;i++) scanf("%s",s);
ll ans=c[n+1][2]*c[m+1][2];
ans+=ans*(ans-1)/2;
ans++;
ans-=c[n+1][2]*c[m+1][2]*(n+m-2);
ans-=2*c[n+1][2]*c[m+1][4]+2*c[m+1][2]*c[n+1][4];
ans-=12*c[n+1][3]*c[m+1][3];
printf("%lld\n", ans);
}
return 0;
}