Codeforces Gym 101190 (NEERC 2016) J. Jenga Boom

题意

长宽高分别为 w , nw , 1 的长方体,每层摆放 n 个形成 nw×nw×1 的底面为正方形的几何体。

每层交替呈 字形加高,共 h 层。

面对几何体的一个棱边,按从近到远令每次的 n 个长方体编号为 1, 2, 3,…

现在依次给出 m 个 l k ,表示第 idx 次,将第 l 层第 k 个长方体去除。

问在第几次操作时会使得几何体倒塌?

解题思路

由于操作顺序给定,且顺序相关,故考虑模拟该操作。对每次操作判断最顶上 top 层的重心位置是否落在 h-top-1层的可稳定范围内。

可稳定范围可视作是该层 [最小编号-0.5, 最大编号+0.5] 整个几何体的一维坐标落在 [0.5, n+0.5]

重心可简单的视作是前 top 层的剩余块的编号和 (等同于坐标和) / 前 top 层的剩余总块数。

其中,由于层次的摆放一次交替呈字形 。故如果对奇数层移除一块长方体,偶数层应特殊处理。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n, w, h, m;
bool flr[2][2501][10001];
int lft[2][2501], rgt[2][2501];
int cet[2][2501], num[2][2501];
int cmp(double x) {
    if(abs(x) < 1e-8)    return 0;
    return x > 0 ? 1 : -1;
}
bool jug(double center, double left, double right) {
    if(cmp(center - left) <= 0 || cmp(center - right) >= 0)
        return false;
    return true;
}
int main()
{
    freopen("jenga.in", "r", stdin);
    freopen("jenga.out", "w", stdout);
    scanf("%d %d %d %d", &n, &w, &h, &m);
    memset(flr, true, sizeof(flr));
    long long lmt = (1+n) * n / 2;
    for(int i=1;i<=h;i++)
    {
        cet[i%2][(i+1)/2] = lmt;
        num[i%2][(i+1)/2] = n;
        lft[i%2][(i+1)/2] = 1;
        rgt[i%2][(i+1)/2] = n;
    }
    for(int idx=1, l, k;idx<=m;idx++)
    {
        scanf("%d %d", &l, &k);
        bool flg = l % 2;
        l = (l+1)/2;
        flr[flg][l][k] = 0;
        cet[flg][l] -= k;
        num[flg][l]--;
        for(int i=1;i<=n;i++)
            if(flr[flg][l][i] == true) {
                lft[flg][l] = i;
                break;
            }
        for(int i=n;i;i--)
            if(flr[flg][l][i] == true) {
                rgt[flg][l] = i;
                break;
            }
        double tCet = 0, tNum = 0;
        for(int i=h;i;i--)
        {
            if(cmp(tNum) == 1 && flg == i%2) {
                double center = tCet * 1.0 / tNum;
                if(jug(center, lft[flg][(i+1)/2] - 0.5, rgt[flg][(i+1)/2] + 0.5) == false) {
                    printf("yes\n%d\n", idx);
                    return 0;
                }
            }
            if(i%2 == flg)
                tCet += cet[flg][(i+1)/2],
                tNum += num[flg][(i+1)/2];
            else
                tCet += num[!flg][(i+1)/2] * (1.0+n)/2.0,
                tNum += num[!flg][(i+1)/2];
        }
    }
    printf("no\n");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值