Codeforces Round #359(div 2)

A:= v =

B:^ w ^

C:一天n个小时,一个小时m分(n,m十进制),一个手表有两部分,左边表示时,右边表示分,但都是7进制,而且手表上最多只能有7个数字且数字不能重复,现在要你算出能正确表示出多少个时间(不够位需要补0)。因为进制只有7,所以可以枚举所有的7进制数,然后再切成7组,分为左边和右边,判断是否符合n,m条件,计数即可。O(7*7^7)

 D:给你一个n个节点的树,有q个询问(n,q<=300000),每次询问一个x,问以x为顶点的子树中,删除哪一个点后使得这个子树剩下的联通块中个数最大的那个中的点数<=原子树点数的一半(答案保证存在,求出一个解即可)。

类似经典的离线LCA,因为询问只跟点个数有关和树形态无关,那么如果节点x的子树答案都出来了,x对应的答案也就出来了(也就是一个树形DP的想法),具体的,x的子树中,个数最大的那个子树中,一定存在一个解(贪心的想法,因为答案一定存在,那么如果最大的那个都不存在,小的就更加不存在),所以f[x]也就在以son[x]为点的子树中。然后如何求出这个呢?是不是就是f[son[x]]呢?那肯定是不一定的。

那么f[x]在f[son[x]]的上方还是下方呢?这其实取决于f[son[x]]在son[x]这个子树中的位置,如果f[son[x]]在子树中偏下(即最大的那个联通块在上方),那么在上面接上更多的点后,如果往f[son[x]]的下方继续寻找,那肯定是不能符合的。如果f[son[x]]在子树中偏上(即最大的那个联通块在下方),那么如果上面接的很少的情况下,也有可能f[x]在f[son[x]]下面的。

难道必须要遍历整个son[x]子树吗?

其实dp是从叶子节点从上做的(叶子节点的f值是自己),所以某个f[x]是这个子树中的什么形态是我们可以人为先确定的,于是我们可以认为确定所有的f[x]都在f[son[x]]上面找,一直保持联通块最大的在上方。于是复杂度就下来了。

#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=300000;
int n,q;
vector<int> g[maxn+50];
int f[maxn+50],size[maxn+50],father[maxn+50],son[maxn+50];
void dfs(int k,int last)
{
    int s=0;
    for(int i=0;i<g[k].size();++i)
    {
        if(g[k][i]==last) continue;
        father[g[k][i]]=k;
        dfs(g[k][i],k);
        size[k]+=size[g[k][i]];
        if(size[g[k][i]]>s) s=size[g[k][i]],son[k]=g[k][i];
    }
}
bool check(int k,int j)
{
    return max(size[k]-size[j],size[son[j]])<=size[k]/2;
}
void dp(int k,int last)
{
    if(g[k].size()==1&&k!=1) 
    {
        f[k]=k;
        return;
    }
    for(int i=0;i<g[k].size();++i) if(g[k][i]!=last) dp(g[k][i],k);
    int j=f[son[k]];
    while(j!=k&&!check(k,j)) j=father[j];
    f[k]=j;
}
int main()
{
    scanf("%d %d",&n,&q);
    for(int i=2;i<=n;++i)
    {
        int x;
        scanf("%d",&x);
        g[x].push_back(i),g[i].push_back(x);
    }
    for(int i=1;i<=n;++i) size[i]=1;
    dfs(1,0);
    dp(1,0);
    int x;
    for(int i=1;i<=q;++i) scanf("%d",&x),printf("%d
",f[x]);
    return 0;
}
View Code

注意下叶子节点的判断,如果考虑是不是只连了一个点的话,那么还有根节点只连1个点的情况,这时候就要特判是不是根节点了……

E:给你一些三维的点,找一个点使得这个点到其他所有点的最大距离最小(曼哈顿距离)

嘻嘻:https://async.icpc-camp.org/d/465-codeforces-round-359

判定一个ans是否可以即判断是否存在一组整数解(X,Y,Z)满足原不等式。

遇到绝对值不等式就去绝对值,用max,min代替,于是本题列出了3个未知数4个不等式的不等式组,判断是否有整数解。解多元的不等式还是要用换元的思想,将Y+Z当作整体,求出Y+Z的取值范围[L,R](与X有关),然后根据两个不同的不等式得到两个不同的[L,R],要让这个存在,于是可以求出X的取值范围,再带入求Y和Z的,判断是否有解。

总结:绝对值要去掉!多元要整体法!(噫~又想到我那可悲的高中数学)

原文地址:https://www.cnblogs.com/wmrv587/p/5615462.html