codeforces Gym - 101190J ——Jenga Boom(模拟)

26 篇文章 0 订阅

一个由1*w*nw的积木构成的长方体,每次抽掉一块,问啥时候会倒塌。

直接模拟每一次抽取,从改层往下计算上面木块的重心,记录每一层最左位置和最右位置,判断重心是否偏离最左或者最右或者在边界上即可。

#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
using namespace std;
const int MAXN=5000+10;



int n,w;
int h,m;

int l,k;
int vis[MAXN][MAXN];
double x[MAXN],y[MAXN];//往上所有层的重心
int num[MAXN];
double L[MAXN],R[MAXN];
double xx[MAXN],yy[MAXN];//每一层的重心
const double EPS=1e-12;
int main(){
    freopen("jenga.in","r",stdin);
    freopen("jenga.out","w",stdout);
    scanf("%d%d%d%d",&n,&w,&h,&m);
    memset(vis,0,sizeof(vis));
    memset(num,0,sizeof(num));
    memset(x,0,sizeof x);
    memset(y,0,sizeof y);
    memset(xx,0,sizeof xx);
    memset(yy,0,sizeof yy);
    num[h+1]=0;
    for(int i=h;i>=1;i--){
        L[i]=0;
        R[i]=n*w;
        num[i]=num[i+1]+n;
        for(int j=1;j<=n;j++){
            x[i]=(n*w*1.0/2.0);
            y[i]=(n*w*1.0/2.0);
            xx[i]=x[i];
            yy[i]=y[i];
        }
    }
    int ok=-1;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&l,&k);
        if(ok!=-1)
            continue;
        vis[l][k]=1;
        for(int j=l;j>=1;j--){//对所有l层往下的num值-1
            num[j]--;
            if(num[j]==num[j+1]||num[h]==0){
                ok=i;
                break;
            }
        }
        if(ok!=-1){
            continue;
        }
        //更新左右端点值
        if(num[l]==num[l+1]){
            ok=i;
            break;
        }else{
            for(int j=1;j<=n;j++){
                if(!vis[l][j]){
                    L[l]=(j-1)*w*1.0;
                    break;
                }
            }
            for(int j=n;j>=1;j--){
                if(!vis[l][j]){
                    R[l]=j*w*1.0;
                    break;
                }
            }
        }
        //对l层计算新的重心
        double temp=0;
        double tmp=0;
        for(int j=1;j<=n;j++){
            if(!vis[l][j]){
                temp+=((j-1)*w+w/2);
                tmp+=1.0;
            }
        }
        temp/=tmp;
        if(l&1){
            xx[l]=temp;
        }else{
            yy[l]=temp;
        }
        for(int j=l;j>=1;j--){
            x[j]=(x[j+1]*num[j+1]+xx[j]*(num[j]-num[j+1]))/num[j];
            y[j]=(y[j+1]*num[j+1]+yy[j]*(num[j]-num[j+1]))/num[j];
            if(j!=h&&(j&1)&&((x[j+1]<=L[j]||x[j+1]>=R[j])||(fabs(x[j+1]-L[j])<EPS)||(fabs(x[j+1]-R[j])<EPS))){
                ok=i;
                break;
            }else if(j!=h&&!(j&1)&&((y[j+1]<=L[j]||y[j+1]>=R[j])||(fabs(x[j+1]-L[j])<EPS)||(fabs(x[j+1]-R[j])<EPS))){
                ok=i;
                break;
            }
        }
    }
    if(ok==-1){
        puts("no");
    }else{
        puts("yes");
        printf("%d\n",ok);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值