hgoi#20191112

T1-牛皮酥

你有一块 \(n×m\) 的饼
每次可以吃某一块饼的一行或一列
问最多可以吃几次

解法

可以发现,每次吃出两个形似 \(1×x\) 的饼最优
然后打表找一下式子

ac代码

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007ll
#define inv_2 500000004ll
using namespace std;
ll n,m;
int main()
{
    freopen("crisp.in","r",stdin);
    freopen("crisp.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    if((n&1)||(m&1))
        n%=mod,m%=mod,printf("%lld\n",(1ll*n*m%mod+n+m-1)*inv_2%mod);
    else n%=mod,m%=mod,printf("%lld\n",(1ll*n*m%mod+n+m-2)*inv_2%mod);
    return 0;
}

T2-传送技术

有一棵有边权的树,现在要构造一个传送系统
每个节点有一个范围 \([l_i,r_i]\) ,节点可以任取一个范围内的数作为参数 \(a_i\)
两个节点之间的传送代价为 \(|a_i-a_j|\)
要求两个节点之间的传送代价均小于直接走的代价
问你能否构造一个这样的系统
如果不能,求最小的 \(x\) 使所有的范围变为 \([l_i-x,r_i+x]\) 后能构造该系统

解法

容易想到,我们只需要检查相邻的点是否符合要求即可
所以对于每一个点,都能从它的儿子处传上来一个范围
如果这些范围全部有解,就可以构造出一个系统
如果不行,我们思考,对于两个区间的交集,如果两个区间全部左右扩大 \(x\)
那么它们的交集也会左右扩大 \(x\) ,所以我们找出最不合法的区间,再算出 \(x\) 即可

ac代码

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define pii pair<int,int>
#define mp make_pair
#define l first
#define r second
using namespace std;
namespace fast_IO
{
    const int IN_LEN = 10000000, OUT_LEN = 10000000;
    char ibuf[IN_LEN], obuf[OUT_LEN], *ih = ibuf + IN_LEN, *oh = obuf, *lastin = ibuf + IN_LEN, *lastout = obuf + OUT_LEN - 1;
    inline char getchar_(){return (ih == lastin) && (lastin = (ih = ibuf) + fread(ibuf, 1, IN_LEN, stdin), ih == lastin) ? EOF : *ih++;}
    inline void putchar_(const char x){if(oh == lastout) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh ++= x;}
    inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);}
    inline void read(int&x)
    {
        int fh=1;x=0;char c=getchar_();
        for(;!isdigit(c);c=getchar_())if(c=='-')fh=-1;
        for(;isdigit(c);c=getchar_())x=x*10+c-'0';
        x*=fh;
    }
    inline void write(int x){if(x>9)write(x/10);putchar_(x%10+'0');}
    inline void writeln(int x){write(x),putchar_('\n');}
};
using namespace fast_IO;
vector<int>e[1000010],w[1000010];
int T,opt,n,x,y,z,ans;
pii a[1000010];
pii f(pii x,int y){return mp(x.l-y,x.r+y);}
pii solve(pii x,pii y){return mp(max(x.l,y.l),min(x.r,y.r));}
void check(pii x){ans=max(ans,x.l-x.r);}
pii dfs(int u,int fa)
{
    pii tmp=a[u];
    int sz=e[u].size();
    for(int i=0;i<sz;i++)if(e[u][i]!=fa)
        check(tmp=solve(tmp,f(dfs(e[u][i],u),w[u][i])));
    return tmp;
}
signed main()
{
  freopen("transport.in","r",stdin);
  freopen("transport.out","w",stdout);
    read(T),read(opt);
    while(T--)
    {
        read(n);
        for(int i=1;i<=n;i++)
            e[i].clear(),w[i].clear();
        for(int i=1;i<=n;i++)read(a[i].l);
        for(int i=1;i<=n;i++)read(a[i].r);
        for(int i=1;i<n;i++)
            read(x),read(y),read(z),
            e[x].pb(y),w[x].pb(z),
            e[y].pb(x),w[y].pb(z);
        ans=0,dfs(1,0),ans=(ans+1)/2;
        printf("%lld\n",opt?ans:(bool)ans);
    }
    return 0;
}

T3-故乡的老树

对于一棵树,求每个节点的子树中,到其他点距离之和最小的点

解法

一棵树中到其他点距离之和最小的点就是树的重心,所以题目转化为求一棵树所有子树的重心
有几个结论(我都不会证QWQ)
一棵树的重心最多有两个,且一定相邻
一棵树的重心一定在它重儿子的重心到根节点的这条链上
对于 \(f_x=max(maxp[x],sz[rt]-sz[x])\) 即重心的定义式
在这条链上一定是一个谷函数,即先减少后增加
然后,我们根据这几条性质直接暴搜就好了QWQ
复杂度是 \(O(n)\) ,我还是不会证嘤嘤嘤

ac代码

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
namespace fast_IO
{
    const int IN_LEN = 10000000, OUT_LEN = 10000000;
    char ibuf[IN_LEN], obuf[OUT_LEN], *ih = ibuf + IN_LEN, *oh = obuf, *lastin = ibuf + IN_LEN, *lastout = obuf + OUT_LEN - 1;
    inline char getchar_(){return (ih == lastin) && (lastin = (ih = ibuf) + fread(ibuf, 1, IN_LEN, stdin), ih == lastin) ? EOF : *ih++;}
    inline void putchar_(const char x){if(oh == lastout) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh ++= x;}
    inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);}
    inline void read(int&x)
    {
        x=0;char c=getchar_();
        for(;!isdigit(c);c=getchar_());
        for(;isdigit(c);c=getchar_())x=x*10+c-'0';
    }
    inline void write(int x){if(x>9)write(x/10);putchar_(x%10+'0');}
    inline void writeln(int x){write(x),putchar_('\n');}
};
using namespace fast_IO;
vector<int>e[1000010],ans[1000010];
int n,x,y,f[1000010],sz[1000010],ct[1000010],maxp[1000010];
void dfs1(int u,int fa)
{
    sz[u]=1,f[u]=fa;
    for(auto v:e[u])if(v!=fa)
        dfs1(v,u),sz[u]+=sz[v],
        maxp[u]=max(maxp[u],sz[v]);
    for(auto v:e[u])if(v!=fa)
        if(sz[v]==maxp[u])ct[u]++;
}
void dfs2(int u,int fa)
{
    int nub;
    for(auto v:e[u])if(v!=fa)
    {
        dfs2(v,u);
        if(sz[v]==maxp[u])nub=v;
    }
    if(ct[u]!=1)ans[u].pb(u);
    else
    {
        int nw=f[ans[nub][0]],lst=ans[nub][0];
        while(nw!=f[u])
        {
            int tmp1=max(sz[u]-sz[nw],maxp[nw]);
            int tmp2=max(sz[u]-sz[lst],maxp[lst]);
            if(tmp1==tmp2){ans[u].pb(lst),ans[u].pb(nw);break;}
            else if(tmp1>tmp2){ans[u].pb(lst);break;}
            lst=nw,nw=f[nw];
        }
        if(!ans[u].size())ans[u].pb(u);
    }
}
int main()
{
    freopen("extree.in","r",stdin);
    freopen("extree.out","w",stdout);
    read(n);
    for(int i=1;i<n;i++)
        read(x),read(y),e[x].pb(y),e[y].pb(x);
    dfs1(1,0),dfs2(1,0);
    for(int i=1;i<=n;i++)
    {
        sort(ans[i].begin(),ans[i].end());
        if(ans[i].size()==1)writeln(ans[i][0]);
        else write(ans[i][0]),putchar_(' '),writeln(ans[i][1]);
    }
    flush();return 0;
}

猜你喜欢

转载自www.cnblogs.com/muronglin/p/hgoi-20191112.html