zoukankan      html  css  js  c++  java
  • 【CodeForces

    @中文题意@

    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
    ", m);
            else if( m % 6 <= 3 )
                printf("%d
    ", m-(m%6));
            else printf("%d
    ", m-(6-m%6));
        }
        else if( n == 2 && m == 2 )
            printf("%d
    ", 0);
        else if( n == 2 && m == 3 )
            printf("%d
    ", 4);
        else if( n == 2 && m == 7 )
            printf("%d
    ", 12);
        else {
            if( n % 2 == 1 && m % 2 == 1 )
                printf("%I64d
    ", 1LL*n*m-1);
            else printf("%I64d
    ", 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
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    人工智能学习笔记003-Python运算符
    人工智能学习笔记002-Python数据类型
    人工智能学习笔记001—python介绍
    dataclasses 笔记
    Js逆向-滑动验证码图片还原
    python3 marshmallow学习
    python 安装 SQLAlchemy 报错
    flask 与 SQLAlchemy的使用
    flask 与 flask_migrate的使用
    flask与flask-script的使用
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9713914.html
Copyright © 2011-2022 走看看