Full_of_Boys训练5总结

题目来源:2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest

A. Advertising Strategy

贪心方法:把一部分k放到初始值,剩下一部分,等到最后用。然后,枚举第一部分放多少即可。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll n,k,ans=1000000000000000000LL;
int main() {
    scanf("%lld %lld",&n,&k);
    if(n<=k) {
        puts("1");return 0;
    }
    for(int t=1;t<=k-1;++t) {
        ll a1=t,tt=1;
        a1 = a1 + min(a1, (n-a1)/2);
        while(a1 < n-k+t) {
            a1 = a1 + min(a1,(n-a1)/2);
            ++tt;
        }
        ++tt;
        ans = min(tt, ans);
    }
    printf("%lld
", ans);
    return 0;
}

C. Carpet

先树剖,构造方法:把重儿子放到当前层的最右端,轻儿子放到下一层,第二次dfs注意顺序,否则会交叉。这样保证高度为logn。。。先是想到如果树低,可以一层层放,我觉得这种题,一种做法就是多手动构造几组解,然后找找规律。另一种思路,就是观察数据范围,20和100000,首先,第一个数很小,就考虑如何降低深度,于是想到了重心,可是感觉没啥用,再怎么调深度也不够,就得朝着把一些比较长的链拿出来,放到一排上这个思路做,那就先求直径,然后,把直径上的点放在第一排,对于这些点延伸出的子树,再求直径,从左到右放在,第二排,递归的再去放第三排,这样应该是有保证的吧,,,写出来wa了。。哎再改改。。然后树剖这个思路相对比较好写吧。。。手懒脑子差。。。只好膜题解。后期也有问题,擅自认怂了,三个人一起刚掉G。。。没有同时开题,现场一定要避免这种问题。还有些时候,A完签到题,就放松了。。。脑子停转的问题,还是很严重。

update :好吧,那个每次求直径的贪心可以卡掉。。。树的长相如下,这可能只是树的一部分,即它的叶子节点也许会连和他类似的结构。显然如果不幸,每次都找到分叉最少的那条直径。树的深度,就没有保证了。。。所以,我们每次怎么算出一棵树中分叉最多的直径呀?bfs的时候处理一下度数和最大的路径?然而还是wa。。。到这好像再想不到树剖就太zz了,保证重链数上界logn条。。。这么优秀的做法。

update:又想了想。。。我每次保证当前这棵树的重心在这一层,选出过重心的最长径or度数和最大路径。。。可以吗???

发现构造题,有些布星啊。有时间多学点组合构造玩。。。

#include <bits/stdc++.h>
const int maxn = 1e5 + 7;
using namespace std;
struct edge{int e,nxt;}E[maxn<<1];
int h[maxn],cc;
void add(int u,int v){
    E[cc].e=v;E[cc].nxt=h[u];h[u]=cc;++cc;
}
int sz[maxn], fa[maxn], son[maxn];
void dfs1(int u,int pre){
    sz[u]=1;
    fa[u]=pre;
    for(int i=h[u];~i;i=E[i].nxt){
        int v=E[i].e;
        if(v!=pre){
            dfs1(v,u);
            sz[u]+=sz[v];
            if(son[u]==-1||sz[v]>sz[son[u]])
                son[u]=v;
        }
    }
}
int X[maxn],Y[maxn],cnt[55];
void dfs2(int u, int d){
    X[u]=++cnt[d];Y[u]=d;
    for(int i=h[u];~i;i=E[i].nxt){
        int v=E[i].e;
        if(v!=son[u]&&v!=fa[u])dfs2(v,d+1);
    }
    if(son[u]==-1)return;
    dfs2(son[u],d);
}
int n,x,y;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)h[i]=son[i]=-1;
    for(int i=1;i<n;++i)scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dfs1(1,0);
    dfs2(1,1);
    for(int i=1;i<=n;++i)cout << X[i] <<' '<<Y[i]<<'
';
    return 0;
}

D. Decoding of Varints

卡unsigned long long。。。注意运算过程

G. God of Winds 

设第一个位置的值为0,然后可以通过递推,求出整张图每个位置的值。check一下,是否矛盾即可。WA点:爆int!!!!这道题,一个难点就是考读题。。。读懂之后,想到把整个图每个位置设成未知数,求解方程,显然会tle。然后,觉得是不每行都能解方程??oldz推了一下,说方程解不了,有一个未知数。反应了半天。其实就是有一个自由项。那我随便设它是什么就行了。然后就可以通过,格子之间的关系推出整张图辣。以后,再也不用int了。。。

H. Hilarious Cooking

发现一定可以构成连续的一段T,那么考虑如何计算出最大值,最小值,再判断一下,是否在区间内就行了。显然,如果只有两端给定,一段区间的最值只受两端影响。那么,分别计算每段的最值加起来就行。注意还有两头要考虑。然后,每段的最值,就可以堆一推公式,o(1)计算了。嘴完了。(感觉挺简单的啊。。除了讨论那块比较麻烦,为啥就没读这题。。不能盲目跟榜哇

原文地址:https://www.cnblogs.com/RRRR-wys/p/9038908.html