【CodeForces - 1034B】Little C Loves 3 II

@中文题意@

n*m的矩阵,当两个点(x1, y1)与(x2, y2)曼哈顿距离为3时可以将两个点匹配。每个点只能够与一个点匹配。求最多能可以匹配多少个点。
n,m <= 10^9

(xi,yi) and (xj,yj) is defined as |xi−xj|+|yi−yj|.

@分析@

【这种题也只能够手算小数据来找规律……】
首先弄清楚一个上界:对于任意的nmn∗m n*mnm矩阵,如果n与m都为奇数,则答案最大为nm-1;否则答案最大为nm。
不妨假设n <= m。
当 n = 1 的时候,我们只能横着进行匹配。我们手算几组数据,可以用如下图的方法可以把161∗6 1*616所有点都匹配。
1*6
再手算几组,我们发现这样一个规律:对于任意一个1m1∗m 1*m1m,如果m%6<=3,则能匹配的点数为m-m%6;否则能匹配的点数为m-6+m%6。
【具体的证明应该可以用归纳法证明,请容许我偷一下懒qwq】

当 n = 2 的时候。222∗2 2*222显然无解,232∗3 2*323的矩阵中间那一列的元素没有任何元素能跟它们匹配,所以最大匹配点数也只能为4。242∗4 2*424,252∗5 2*525可以采用下列所示的方法全部匹配完。
2*42*5
262∗6 2*626矩阵可以把它拆成两个161∗6 1*616的矩阵,每个矩阵内部可以全部匹配完。
然后!学长们就是被272∗7 2*727的矩阵卡掉了。实际上272∗7 2*727不能构造出全部匹配的情况的。如图:两个蓝色块只能与两个紫色块匹配,所以紫色块只能与蓝色块匹配。同理,两个红色块只能与两个棕色块匹配,所以棕色块只能与红色块匹配。然后有一个块既要和蓝色块匹配又要和棕色块匹配,所以不可能~
2*7(1)2*7(2)
所以272∗7 2*727最多只能配对12个点。
然后,最关键的来了。对于一个2m2∗m 2*m2m(m>=7),如果m为偶数,我们可以把m拆成若干个4与6的和,即将原矩阵拆成若干个242∗4 2*424矩阵与262∗6 2*626矩阵。对于这些矩阵我们可以把所有点匹配完,所以我们自然也就可以匹配完2m2∗m 2*m2m的所有点;反之,如果m为奇数,我们可以先将2m2∗m 2*m2m分成252∗5 2*525与2(m5)2∗(m−5) 2*(m-5)2(m5)两个部分,252∗5 2*525可以匹配完。又因m-5是个偶数,所以奇数也可以得到相似的结论。
即:2mm>=72∗m(m>=7) 2*m(m&gt;= 7)2mm>=7)的矩阵,答案总可以达到上界2m2∗m 2*m2m

下一步,当n = 3的时候。
333∗3 3*333,343∗4 3*434,353∗5 3*535的构造如下:
3*33*43*5
363∗6 3*636就可以分成3个161∗6 1*616拼出,就不画图了。
于是,对于一个3m3∗m 3*m3m的矩阵,一样地,如果m是偶数,就将m拆成若干个4与6的和;否则就拆成(m-3)与3。所以,3mm>=33∗m(m>=3) 3*m(m&gt;=3)3mm>=3)的答案也总是可以达到上界

对于n = 4,我们已知424∗2 4*242,434∗3 4*343可以构造出来。444∗4 4*444可以拆成两个424∗2 4*242。类似的推理,4mm>=44∗m(m>=4) 4*m(m&gt;=4)4mm>=4)的答案总可以达到上界。

对于n = 5,我们已知525∗2 5*252,535∗3 5*353,545∗4 5*454可以构造出来。因此5mm>=55∗m(m>=5) 5*m(m&gt;=5)5mm>=5)的答案总可以达到上界。

对于n = 6,我们已知616∗1 6*161可以构造出来。因此6mm>=66∗m(m>=6) 6*m(m&gt;=6)6mm>=6)的答案总可以达到上界。

然后,对于n>6。如果n为偶数,可以把n拆成若干个4与6的和;否则如果m为偶数,可以把n拆成若干个4与6的和;否则,可以把n拆成(n-3)与3,然后重复上面的推理。因此nmn>6,m>nn∗m(n>6,m>n) n*m(n&gt;6, m&gt;n)nmn>6,m>n)的答案总可以达到上界。

至此,本题就Over了。

@代码@

#include<cstdio>
#include<algorithm>
using namespace std;
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    if( n > m ) swap(n, m);
    if( n == 1 ) {
        if( m % 6 == 0 )
            printf("%d\n", m);
        else if( m % 6 <= 3 )
            printf("%d\n", m-(m%6));
        else printf("%d\n", m-(6-m%6));
    }
    else if( n == 2 && m == 2 )
        printf("%d\n", 0);
    else if( n == 2 && m == 3 )
        printf("%d\n", 4);
    else if( n == 2 && m == 7 )
        printf("%d\n", 12);
    else {
        if( n % 2 == 1 && m % 2 == 1 )
            printf("%I64d\n", 1LL*n*m-1);
        else printf("%I64d\n", 1LL*n*m);
    }
}
View Code

 

 

另外解法:

这道题…

可以说是打表吧

首先我们可以观察到,对于任意一个161∗6 1*616或者242∗4 2*424的格子,都是可以填满的,

那也就说如果有一边长能被6或者4给整除,那就是可以填满的

然后对于5*5以下的了,我们可以直接打表预处理出来(因为有一些特殊情况吧)

#include<bits/stdc++.h>

using namespace std ;
int D[5][5]={ {0,0,0,2,4},
               {0,0,4,8,10},
               {0,4,8,12,14},
               {2,8,12,16,18},
               {4,10,14,18,24}};
int main( )
{
    int n,m;
    scanf("%d%d",&n,&m);
    if(n<m)
    swap(n,m);
    long long ans=0;
    if(m==1)
    {
        ans+=n/6*6;
        n=n%6;
        ans+=D[0][n-1];
    }
    else if(n%4==0 || m%4==0)
    ans=(long long )n*m;
    else if(n%6==0 || m%6==0)
    ans=(long long )n*m;
    else if(n==7&&m==2)
    ans=12;
    else if(n<=5&&m<=5)
    ans=D[n-1][m-1];
    else
        ans=(long long )n*m/2*2;
    printf("%I64d\n",ans);
    return 0;
}
View Code

 

posted @ 2018-09-27 16:36  shuai_hui  阅读(630)  评论(0编辑  收藏  举报