• 打地鼠加强版(Shrew)


    题目描述

    打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中。玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地鼠越多分数也就越高。

    游戏中的锤子每次只能打一只地鼠,如果多只地鼠同时探出头,玩家只能通过多次挥舞锤子的方式打掉所有的地鼠。你认为这锤子太没用了,所以你改装了锤子,增加了锤子与地面的接触面积,使其每次可以击打一片区域。如果我们把地面看做m*n的方阵,其每个元素都代表一个地鼠洞,那么锤子可以覆盖R*C区域内的所有地鼠洞。但是改装后的锤子有一个缺点:每次挥舞锤子时,对于这R*C的区域中的所有地洞,锤子会打掉恰好一只地鼠。也就是说锤子覆盖的区域中,每个地洞必须至少有1只地鼠,且如果某个地洞中地鼠的个数大于1,那么这个地洞只会有1只地鼠被打掉,因此每次挥舞锤子时,恰好有R*C只地鼠被打掉。由于锤子的内部结构过于精密,因此在游戏过程中你不能旋转锤子(即不能互换R和C)。

    你可以任意更改锤子的规格(即你可以任意规定R和C的大小),但是改装锤子的工作只能在打地鼠前进行(即你不可以打掉一部分地鼠后,再改变锤子的规格)。 你的任务是求出要想打掉所有的地鼠,至少需要挥舞锤子的次数。 Hint:由于你可以把锤子的大小设置为1*1,因此本题总是有解的。

    输入

    输入文件第一行包含两个正整数m和n。

    下面m行每行n个正整数描述地图,每个数字表示相应位置的地洞中地鼠的数量。

    输出

    输出文件仅一个整数,表示最少的挥舞次数。

    样例输入

    3 3 1 2 1 2 4 2 1 2 1

    样例输出

    4

    提示

    60%数据n,m<=100. 
    80%数据n,m<=500. 
    100%数据n,m<=1000,其他数在0~10^6范围内。

    发现行列独立。那么对行列暴力。

    #pragma GCC optimize("-Ofast")
    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    LL minn,f[1005][1005],sss;
    int n,m,a[1005][1005];
    bool pdd(int x,int y){
    //  if (sss>=(1ll*x*y*minn)) return;
        memset(f,0,sizeof f); LL s=0,t=0;
        for (int i=1;i<=n-x+1;i++){
            for (int j=1;j<=m-y+1;j++){
                t=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
                if (i>=x) t-=f[i-x][j];
                if (j>=y) t-=f[i][j-y];
                if (i>=x&&j>=y) t+=f[i-x][j-y];
                if (t>a[i][j]) return 0;
                f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+a[i][j]-t;
                s+=a[i][j]-t;
            }
            for (int j=m-y+2;j<=m;j++)
                f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
        }
        for (int i=n-x+2;i<=n;i++)
            for (int j=1;j<=m;j++)
                f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++){
                t=f[i][j];
                if (i>=x) t-=f[i-x][j];
                if (j>=y) t-=f[i][j-y];
                if (i>=x&&j>=y)   t+=f[i-x][j-y];
                if (t!=a[i][j]) return 0;
            }
    //  if (s<minn) minn=s;
        return 1;
    }
    int l,r;
    signed main(){
    //  freopen("shrew.in","r",stdin);
    //  freopen("shrew.out","w",stdout);
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                scanf("%d",&a[i][j]),sss+=a[i][j];
        minn=1ll<<42;
        for (int i=n;i;i--) if (sss%i==0&&pdd(i,1)) {
            l=i; break;
        } 
        for (int i=m;i;i--) if (sss%i==0&&pdd(1,i)) {
            r=i; break;
        }
        printf("%lld
    ",sss/l/r);
        return 0;
    }
  • 相关阅读:
    [LeetCode] Power of Three 判断3的次方数
    [LeetCode] 322. Coin Change 硬币找零
    [LeetCode] 321. Create Maximum Number 创建最大数
    ITK 3.20.1 VS2010 Configuration 配置
    VTK 5.10.1 VS2010 Configuration 配置
    FLTK 1.3.3 MinGW 4.9.1 Configuration 配置
    FLTK 1.1.10 VS2010 Configuration 配置
    Inheritance, Association, Aggregation, and Composition 类的继承,关联,聚合和组合的区别
    [LeetCode] Bulb Switcher 灯泡开关
    [LeetCode] Maximum Product of Word Lengths 单词长度的最大积
  • 原文地址:https://www.cnblogs.com/rrsb/p/9489561.html
Copyright © 2020-2023  润新知