• [JLOI2015] 城池攻占


    题目

    原题地址

    解说

    首先发现乘的时候 系数不会为负,所以能得到一个关键条件:变化后的战斗力随变化前的战斗力大小单调
    所以我们考虑倍增
    设hp[x][i]是从x开始一路攻克(2^i)个城池所需要最小的初始生命值
    设trans[x][i][0/1]是攻克了(2^i)个城池后攻击力的变化量,0表示乘,1表示加,先乘后加
    注意乘的系数初始化成1
    然后就可以倍增了
    然而空间大小恶意卡倍增
    但是我们这个倍增可以换成三进制的
    就是把定义里的(2^i)都换成(3^i)
    于是(log_3300000=10),空间就变成了原来的一半
    需要注意的一点是,最后在跳倍增的时候,同一个长度可以跳两次(因为是三进制嘛),循环的时候稍微注意一下

    代码

    #include<bits/stdc++.h>
    #define pa pair<ll,ll>
    #define CLR(a,x) memset(a,x,sizeof(a))
    #define MP make_pair
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+5;
    
    inline char gc(){
    	return getchar();
    	static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
    }
    inline ll rd(){
        ll x=0;char c=gc();bool neg=0;
        while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
        while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
        return neg?(~x+1):x;
    }
    
    int N,M,fa[maxn][11];
    ll hp[maxn][11],trans[maxn][11][2];
    int ans1[maxn],ans2[maxn];
    int pw3[11];
    
    int main(){
        //freopen("","r",stdin);
        int i,j,k;
        pw3[0]=1;for(i=1;i<=10;i++) pw3[i]=pw3[i-1]*3;
        N=rd(),M=rd();
        for(i=1;i<=N;i++) hp[i][0]=rd();
        fa[1][0]=N+1;
        for(i=2;i<=N;i++){
        	fa[i][0]=rd();
        	ll x=rd(),y=rd();
        	trans[i][0][0]=1;
        	trans[i][0][!x]=y;
        	for(j=0;j<10;j++){
        		int f=fa[i][j],ff=fa[f][j];
        		if(!f||!ff||!fa[ff][j]) break;
        		fa[i][j+1]=fa[ff][j];
        		ll hp1=max(hp[f][j],(ll)ceil(1.0*(hp[ff][j]-trans[f][j][1])/trans[f][j][0]));
        		hp[i][j+1]=max(hp[i][j],(ll)ceil(1.0*(hp1-trans[i][j][1])/trans[i][j][0]));
        		trans[i][j+1][1]=trans[i][j][1]*trans[f][j][0]+trans[f][j][1];
        		trans[i][j+1][0]=trans[i][j][0]*trans[f][j][0];
        		trans[i][j+1][1]=trans[i][j+1][1]*trans[ff][j][0]+trans[ff][j][1];
        		trans[i][j+1][0]=trans[i][j+1][0]*trans[ff][j][0];
        	}
        }
        for(i=1;i<=M;i++){
        	ll s=rd();int x=rd(),n=0;
        	for(j=10;j>=0&&x!=-1;j--){
        		if(fa[x][j]&&hp[x][j]<=s){
        			s=s*trans[x][j][0]+trans[x][j][1];
        			x=fa[x][j];
        			n+=pw3[j];j++;
        		}
        	}
        	if(x!=-1) ans1[x]++;
        	ans2[i]=n;
        }
        for(i=1;i<=N;i++)
        	printf("%d
    ",ans1[i]);
        for(i=1;i<=M;i++)
        	printf("%d
    ",ans2[i]);
        
        return 0;
    }
    

    幸甚至哉,歌以咏志。

  • 相关阅读:
    单变量线性回归
    【记】国奖交流会
    转【研究生第一篇学术论文常犯问题总结】
    this.$confirm里面使用await异步调取接口数据
    margin和padding的值是百分比的时候是怎么计算的?
    原生js实现三级联动下拉框
    两个数组里面的对象元素根据相同的id合并到一个数组
    制作遮罩层的样式
    自定义表单验证方法的使用
    封装获取操作系统和浏览器类型的方法
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12928854.html
Copyright © 2020-2023  润新知