USACO 2017 January Platinum

Posted ditoly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了USACO 2017 January Platinum相关的知识,希望对你有一定的参考价值。

因为之前忘做了,赶紧补上。

 

T1.Promotion Counting

题目大意:给定一个以1为根的N个节点的树(N<=100,000),每个节点有一个权值,对于每个节点求出权值比它大的子孙的个数。

思路:肯定先要求出dfs序,首先无脑想到主席树,后来发现只要按权值从大到小处理就不用那么麻烦了。

#include<cstdio>
#include<algorithm>
using namespace std;
char B[1<<26],*S=B,C;int X;
inline int read()
{
    while((C=*S++)<0||C>9);
    for(X=C-0;(C=*S++)>=0&&C<=9;)X=(X<<3)+(X<<1)+C-0;
    return X;
}
#define MN 100000
#define lb(x) (x&-x)
struct edge{int nx,t;}e[MN+5],p[MN+5];
int h[MN+5],en,d[MN+5],o[MN+5],cnt,s[MN+5],ans[MN+5];
bool cmp(edge a,edge b){return a.t>b.t;}
inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;}
void pre(int x)
{
    d[x]=++cnt;
    for(int i=h[x];i;i=e[i].nx)pre(e[i].t);
    o[x]=cnt;
}
inline void inc(int x){for(;x<=MN;x+=lb(x))++s[x];}
inline int sum(int x){int r=0;for(;x;x-=lb(x))r+=s[x];return r;}
int main()
{
    fread(B,1,1<<26,stdin);
    int n=read(),i;
    for(i=1;i<=n;++i)p[i]=(edge){i,read()};
    sort(p+1,p+n+1,cmp);
    for(i=2;i<=n;++i)ins(read(),i);
    pre(1);
    for(i=1;i<=n;++i)
    {
        ans[p[i].nx]=sum(o[p[i].nx])-sum(d[p[i].nx]);
        inc(d[p[i].nx]);
    }
    for(i=1;i<=n;++i)printf("%d\n",ans[i]);
}

 

T2.Building a Tall Barn

题目大意:给定长度为N的序列ai,对每个ai分配ci使得ci>0且ci之和等于K,求出最小的ai/ci之和。(N<=100,000,K<=10^12)

思路:容易想到先给每个ai分1,用堆维护每个ai再多分1能获得的收益,O(KlogN)实现。也就相当于N堆物品,从中取走K个求最大收益,我们二分一个取的下界,把大于这个下界的都取走,看看取了几个就可以了,取几个我一开始也二分,T了,然后发现可以数学直接算。另外这题精度要求可能比较大,二分多分几次就行了,最后O(NlogK)。从题解中学到了种二分写法(虽然好像以前见识过):for(i=1;i<=100;++i)if(check(mid))...

#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
#define ll long long
char B[1<<26],*S=B,C;ll X;
inline ll read()
{
    while((C=*S++)<0||C>9);
    for(X=C-0;(C=*S++)>=0&&C<=9;)X=(X<<3)+(X<<1)+C-0;
    return X;
}
#define MN 100000
ll k,a[MN+5];
ll cal(double x){return (ll)((sqrt(1+4*x)-1)/2);}
int main()
{
    fread(B,1,1<<26,stdin);
    int n=read(),i;k=read()-n;double l,r,mid;ll cnt;
    for(i=1;i<=n;++i)a[i]=read();
    for(l=0,r=1e12;r-l>1e-12;)
    {
        mid=(l+r)/2;
        for(cnt=0,i=1;i<=n;++i)cnt+=cal(a[i]/mid);
        if(cnt<=k)r=mid;else l=mid;
    }
    for(i=1,l=0;i<=n;++i)l+=a[i]/(double)(cal(a[i]/r)+1);
    cout<<(ll)(l+0.5);
}

 

T3.Subsequence Reversal

题目大意:给定一个长度为N的序列,允许翻转一个子序列,求最长不下降子序列长度。(N<=50,序列元素在1..50内)

思路:一眼看上去很不可做,而且N这么小很吓人,仔细想想可以搞个类似区间DP,从整个序列开始,左边一个元素不翻或右边一个元素不翻或交换这两个元素,逐渐把区间缩小,然后再在状态里加上能取的数字区间,还是挺好转移的,复杂度O(N^2*maxai^2),另外题目里明明写的increasing却是不下降,很坑爹啊。

#include<cstdio>
#include<algorithm>
using namespace std;
char B[1<<26],*S=B,C;int X;
inline int read()
{
    while((C=*S++)<0||C>9);
    for(X=C-0;(C=*S++)>=0&&C<=9;)X=(X<<3)+(X<<1)+C-0;
    return X;
}
#define MN 50
int a[MN+5],f[MN+5][MN+5][MN+5][MN+5],ans;
inline void r(int&a,int b){if(b>a){a=b;if(b>ans)ans=b;}}
int main()
{
    fread(B,1,1<<26,stdin);
    int n=read(),i,j,k,l;
    for(i=1;i<=n;++i)a[i]=read();
    for(i=1;i<=n;++i)for(j=n;j>=i;--j)
        for(k=1;k<=MN;++k)for(l=MN;l>=k;--l)
        {
            if(k<=a[i]&&a[i]<=l)
                r(f[i+1][j][a[i]][l],f[i][j][k][l]+1),
                r(f[i+1][j-1][k][a[i]],f[i][j][k][l]+1);
            if(k<=a[j]&&a[j]<=l)
                r(f[i][j-1][k][a[j]],f[i][j][k][l]+1),
                r(f[i+1][j-1][a[j]][l],f[i][j][k][l]+1);
            if(i<j&&k<=a[j]&&a[j]<=a[i]&&a[i]<=l)
                r(f[i+1][j-1][a[j]][a[i]],f[i][j][k][l]+2);
            r(f[i+1][j][k][l],f[i][j][k][l]);
            r(f[i][j-1][k][l],f[i][j][k][l]);
            r(f[i][j][k+1][l],f[i][j][k][l]);
            r(f[i][j][k][l-1],f[i][j][k][l]);
        }
    printf("%d",ans);
}

 

以上是关于USACO 2017 January Platinum的主要内容,如果未能解决你的问题,请参考以下文章

USACO JANUARY——矩形[rects]

USACO 2019 January Contest, Platinum

USACO 2020 January Contest, Platinum Problem 1. Cave Paintings

USACO 2016 January Contest Fort Moo (bzoj4506)

100130. USACO 2018 January Platinum鱼池逃脱Cow at Large

USACO 2019 January Contest Platinum T3: Train Tracking 2