【SJTUOJ笔记】P1055 二哥切巧克力

https://acm.sjtu.edu.cn/OnlineJudge/problem/1055
先明确一下重心的公式。在这道题中,从 (x,y) ( x , y ) (p,q) ( p , q ) 的一块长方形巧克力的重心 (xG,yG) ( x G , y G ) 位于

xG=pi=x(iqj=yρ(i,j))pi=xqj=yρ(i,j), yG=qj=y(jpi=xρ(i,j))pi=xqj=yρ(i,j). x G = ∑ i = x p ( i ∑ j = y q ρ ( i , j ) ) ∑ i = x p ∑ j = y q ρ ( i , j ) ,   y G = ∑ j = y q ( j ∑ i = x p ρ ( i , j ) ) ∑ i = x p ∑ j = y q ρ ( i , j ) .

简单来说,就是坐标用质量(这里用密度代替)加权平均。
看到这题,我的第一思路是做质量的前缀和,然后枚举大小和左上角进行计算。但这样做的极限时间大概是 300×23k=300k(301k)2=4×1011 300 × 2 ∑ k = 300 3 k ( 301 − k ) 2 = 4 × 10 11 ,必定会超时。于是经过了对重心计算式的仔细观察,发现分子上的加权平均也可以通过前缀和的方式直接计算,这样就把验证某个方案是否可行的时间复杂度从 O(k3) O ( k 3 ) 降到了 O(1) O ( 1 ) ,仅剩的枚举复杂度是 O(cr×min(c,r)) O ( c r × min ( c , r ) ) 。虽然题目里没有说一共有多少组数据,但应该是不会超时的。
最后,通过前缀和计算重心位置时,注意把正方形的四个角去掉,还要注意质量和为零的情况。
核心部分如下:


        int a[305][305], sum[305][305];
        int sumx[305][305], sumy[305][305];
        //sum表示简单的质量和,sumx表示x方向的加权平均,sumy表示y方向的加权平均
   //=======================================
        for (int i = 1; i <= r; ++i){
            for (int j = 1; j <= c; ++j){
                cin >> ch;
                a[i][j] = ch - '0';
                sum[i][j] = a[i][j] + sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1];
            }
        }
        for (int i = 1; i <= r; ++i){
            for (int j = 1; j <= c; ++j){
                sumx[i][j] = sumx[i - 1][j] + i * (sum[i][j] - sum[i - 1][j]);
                sumy[i][j] = sumy[i][j - 1] + j * (sum[i][j] - sum[i][j - 1]);
            }
        }
   //==========================================
        for (int k = min(r, c); k >= 3; --k){
            for (int i = 1; i <= r - k + 1; ++i){
                for (int j = 1; j <= c - k + 1; ++j){
                    int x = i + k - 1, y = j + k - 1;
                    int s = sum[x][y] - sum[i - 1][y] - sum[x][j - 1] + sum[i - 1][j - 1]
                            - a[i][j] - a[i][y] - a[x][j] - a[x][y];
                    double wx = sumx[x][y] - sumx[i - 1][y] - sumx[x][j - 1] + sumx[i - 1][j - 1]
                            - i * a[i][j] - i * a[i][y] - x * a[x][j] - x * a[x][y];
                    double wy = sumy[x][y] - sumy[i - 1][y] - sumy[x][j - 1] + sumy[i - 1][j - 1]
                            - j * a[i][j] - y * a[i][y] - j * a[x][j] - y * a[x][y];
                    if (s == 0){.../*成立*/}
                    wx = wx / s;
                    wy = wy / s;
                    if (abs(2 * wx - i - x) < 1e-8 && abs(2 * wy - j - y) < 1e-8){.../*成立*/}
                }
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值