zoukankan      html  css  js  c++  java
  • 列宁格勒—诺夫哥罗德战役

    特殊数据p=1,当然就把所有点权求和就是答案

    因为是要最小化进攻次数

    考虑到打下面的上面死不了,不妨先把上面的打死

    贪心正确性显然

    然后从上到下,算出当前这个打几下死,把伤害传递下去,这样就有70%的分了(数据造水了)

    1000000的数据,考虑线性解法

    看这个式子Max(0,p-dis(i,j)^2)

    因为j在i的子树内

    所以等价于Max(0,p-(deep[i]-deep[j])^2)

    考虑一个点j受到的来自祖先的伤害

    Hurt=∑(p-(deep[i]-deep[j])^2)((deep[i]-deep[j])^2<p)

    =∑(p-deep[j]^2-deep[i]^2+2*deep[i]*deep[j])((deep[i]-deep[j])^2<p)

    其中,p,deep[j]是已知量,我们在递归时只要记录有效伤害个数,有效伤害深度和,有效伤害深度平方和即可

    理解了解法,具体实现还是很简单的,这里就不在赘述

    难看的代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #define int long long
    #define ll long long
    using namespace std;
    const int maxn=1e6+10;
    struct edge{
        int next,to;
    }e[maxn*2];
    int n,num[maxn],head[maxn],cnt,line[maxn],d[maxn],dis,cnts[maxn],m[maxn];
    ll sum[maxn],sump[maxn],mid;
    inline void add(int x,int y)
    {
        e[++cnt].next=head[x];
        e[cnt].to=y;
        head[x]=cnt;
    }
    void dfs(int x,int pre,int deep)
    {
        d[x]=deep;
        if(d[x]>dis)
        {
            int tmp=d[x]-dis;
            line[x]-=cnts[tmp];
            sum[x]-=(ll)cnts[tmp]*tmp;
            sump[x]-=(ll)cnts[tmp]*tmp*tmp;
        }
        ll all=line[x]*(mid-(ll)d[x]*d[x])-sump[x]+2*d[x]*sum[x];
        if(m[x]>=all)
        {
            num[x]=(m[x]-all)/mid+1;
            cnt+=num[x];
        }
        cnts[d[x]]=num[x];
        for(int v,i=head[x];i;i=e[i].next)
            if((v=e[i].to)!=pre)
            {
                line[v]=line[x]+num[x];
                sum[v]=sum[x]+(ll)num[x]*d[x];
                sump[v]=sump[x]+(ll)num[x]*d[x]*d[x];
                dfs(v,x,deep+1);
            }
    }
    inline void check()
    {
        cnt=0,dis=ceil(sqrt(mid));
        dfs(1,0,1);
    }
    int readn()
    {
        int x=0;
        char c=getchar();
        while(c<'0'||c>'9')
            c=getchar();
        while(c>='0'&&c<='9')
        {
            x=(x<<3)+(x<<1)+(c^'0');
            c=getchar();
        }
        return x;
    }
    signed main()
    {
        n=readn(),mid=readn();
        for(int i=1;i<=n;i++)
            m[i]=readn();
        for(int x,y,i=1;i<n;i++)
        {
            x=readn(),y=readn();
            add(x,y),add(y,x);
        }
        check();
        printf("%lld
    ",cnt);
        return 0;
    }
  • 相关阅读:
    GNU make manual 翻译(九十九)
    GNU make manual 翻译( 九十五)
    Shell的 for 循环小例子
    makefile中对目录遍历的小例子
    GNU make manual 翻译(九十三)
    GNU make manual 翻译( 一百)
    GNU make manual 翻译( 九十七)
    GNU make manual 翻译( 九十八)
    mapserver4.8.3 的readme.win32的中文翻译文件
    遥控器编程
  • 原文地址:https://www.cnblogs.com/ivanovcraft/p/9664541.html
Copyright © 2011-2022 走看看