Reverse It(HDU-6513)


题意

  给定一个 n × m n \times m n×m的网格,每个网格都放置一张牌。每次选定一个矩形框,然后将这个矩形框内所有牌都反转。问:最多反转两次,可以产生多少种情况。
  链接:link


思路

  题目要求翻转次数不超过两次:

翻转次数情况总数
01
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+m2)

    
    
    
    

  包含了 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值