• Codeforces 1340D. Nastya and Time Machine 题解


    题目连接:D. Nastya and Time Machine

    题目大意:给你一棵树,通过每条边需要(1)的时间,你可以在一个结点处将时间变为任意一个比当前时间小的非负整数,要求满足以下两个限制:

    • 经过每个节点至少一次
    • 每一个节点上,到达它的时间(更改时的时间也计算在内)不得重复
      求出任意一种使得到达每个节点的时间最大值最小。

    题解:最大最小,直接二分答案上啊。要求出一种方案,这题二分答案不大好做,考虑直接构造。

    首先考虑单纯的走(即不考虑修改时间),每个节点很明显经过的次数是它的度数次,并且,如果考虑修改时间,若修改一次时间不算经过该节点一次的话,那么经过该节点的时间肯定是度数次(多了只会给自己加负担)。

    那么先考虑确定下答案,二分答案多好啊(博主这个菜鸡只会二分答案了),首先,很明显最终答案肯定不小于每个点的度数中的最大值,所以答案就是每个点的度数的最大值减一(因为从(0)开始)……吗?样例就推翻了我们的这个结论。

    仔细考虑,每个点很明显最小是它的度数减一,但是问题在于如果进入这个点时的时间不为(0),那么就需要更改一次时间,但是更改时间又会导致当前点时间个数的浪费,所以更改时间自然是越少越好,但因为更改时间不可避免,所以考虑每一个点能否最多只用一次更改时间,这样的话答案就是每个点的度数的最大值。

    (maxdeg=max_{u} deg_u ext{(} deg_u ext{表示节点}u ext{的度数)}),那么考虑让每一个点的时间取值为([maxdeg-deg_u,maxdeg]),一共有(deg_u+1)中取值,满足我们的要求。

    接下来就是考虑怎么构造答案了,因为我们钦定每一个节点的时间取值是在一个范围内,所以到儿子的时间就要连续(将该区间看成一个环),因为只能更改一次时间,这可以在当前时间到达(maxdeg)时更改为(maxdeg-deg_u),然后这题就做完了(有一些简单的情况就不列了)。

    下面是代码:

    #include <cstdio>
    void read(int &a){
    	a=0;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		a=(a<<1)+(a<<3)+(c^48);
    		c=getchar();
    	}
    }
    int max(int a,int b){
    	return a>b?a:b;
    }
    const int Maxn=100000;
    int n,ans;
    int fa[Maxn+5];
    int head[Maxn+5],arrive[Maxn<<1|5],nxt[Maxn<<1|5],tot;
    void add_edge(int from,int to){
    	arrive[++tot]=to;
    	nxt[tot]=head[from];
    	head[from]=tot;
    }
    int deg[Maxn+5];
    struct Operation{
    	int u,t;
    }op[Maxn<<2|5];
    int len;
    void work_dfs(int u,int t){
    	op[++len].u=u;
    	op[len].t=t;
    	int last=t;
    	bool flag=0;
    	if(last==ans){
    		last=ans-deg[u];
    		flag=1;
    	}
    	for(int i=head[u];i;i=nxt[i]){
    		int v=arrive[i];
    		if(v==fa[u]){
    			continue;
    		}
    		fa[v]=u;
    		if(flag){
    			op[++len].u=u;
    			op[len].t=last;
    			flag=0;
    		}
    		work_dfs(v,++last);
    		op[++len].u=u;
    		op[len].t=last;
    		if(last==ans){
    			last=ans-deg[u];
    			flag=1;
    		}
    	}
    	if(flag){
    		last=ans;
    	}
    	if(u!=1&&last!=t-1){
    		op[++len].u=u;
    		op[len].t=t-1;
    	}
    }
    int main(){
    	read(n);
    	for(int i=1;i<n;i++){
    		int u,v;
    		read(u),read(v);
    		add_edge(u,v);
    		add_edge(v,u);
    		deg[u]++,deg[v]++;
    	}
    	for(int i=1;i<=n;i++){
    		ans=max(ans,deg[i]);
    	}
    	work_dfs(1,0);
    	printf("%d
    ",len);
    	for(int i=1;i<=len;i++){
    		printf("%d %d
    ",op[i].u,op[i].t);
    	}
    	return 0;
    }
    
  • 相关阅读:
    帮助你生成分享和显示社交媒体网络按钮的jQuery插件 #50C1AL java程序员
    Storyboard多View的切换 [xcode 4.4.1]
    ObjectiveC Enum 枚举数据类型解析
    在IOS中使用KeychainItemWrapper保存用户名和密码实现记住密码功能
    10个迷惑新手的Cocoa&Objectivec开发问题
    关于分类(category)和类的扩展(extensions)的验证
    解决mac创建的压缩包,window下解压乱码的问题
    xcode快捷键大全
    解决Shockwave flash在chrome浏览器上崩溃的问题
    嵌入式内核与文件系统烧写
  • 原文地址:https://www.cnblogs.com/withhope/p/12790266.html
Copyright © 2020-2023  润新知