zoukankan      html  css  js  c++  java
  • SDOI2018一轮NOI培训 题目整理

    (qwq)首先,这些题对于我而言……类似于(emmm)洪水猛兽

    (mathcal{Day 1})

    T1

    (mathcal{color{red}{Description}})

    作为钦钦草原最绿的男人,杨某针每天都要开车巡视钦钦草原一圈。钦钦草原由 (n) 个城市组成, (m) 条双向道路连接着它们。经过第 (i) 条道路要花费的
    时间是 (2^i)

    杨某针想要经过每条道路至少一次,在此基础上他想最小化他花费的时间。但作为曾经 (CTSC)(Cu) 选手,他并不能很快地计算出这个问题。所以他向你求助。

    【输入格式】
    从文件 (carcar.in) 中读入数据。

    输入第一行包含两个正整数 (n, m)

    接下来 (m) 行,每行两个正整数 (a_i, b_i),表示第 (i) 条边连接点 (a_i)(b_i),它的权值为 (2^i)

    保证 (a_i ,b_i),不存在重边,且任意两个点之间可以互相到达。

    【输出格式】
    输出到文件 (carcar.out) 中。

    输出一行一个整数,表示答案对 (10^9 + 7) 取模的值。

    (mathcal{color{red}{Solution}})

    首先我们要认识到,这个题类似于求一个欧拉路这么一个东西。但是要求遍历所有的边并回到出发点,那么这不就是传说中的——一笔画问题吗qwq?

    嗯,那就是欧拉图了!即,如果你想对一个图进行一笔画,那么首先你需要它是一个偶图,意思就是需要这个图上,度数为奇数的点的个数为0或者为2。我们再考虑,一条路径在最优情况下,至多通过两次,因为通过三次就等同于通过一次,以此类推。

    那,首先我们需要对这张图进行重构,如果不是一张偶图的话,我们就要添一条边。那添边怎么添呢?当然是贪心地、单调地添边啦!所以不妨在最小生成树中选边。而对于这种贪心的方式,由于它的边权是2的次幂,所以因为$$sumlimits_{i = 1}^{n - 1}{2^i} < 2^n$$,可以保证贪心地添边是没错的,因为无论怎么添边,之后的一定没有之前的更优。

    于是结束,撒花花!

    至于代码,就是一遍(dfs)加上一次最小生成树,时间复杂度(O(n + m)),完全可以接受。有些有意思的小细节也是可圈可点的(qwq).

    const int maxn=401000;
    const int mod=1e9+7;
    struct node{
    	int point;
    	int weight;
    	int nxt;
    };
    node line[maxn<<1];
    int head[maxn],tail;
    int ans=0;
    int deg[maxn];
    void add(int a,int b,int c){
    	line[++tail].point = b;
    	line[tail].weight = c;
    	line[tail].nxt = head[a];
    	head[a] = tail;
    }
    int f[maxn];
    int find(int x){
    	return f[x] == x ? x : f[x] = find(f[x]) ;
    }
    bool _union(int a,int b){
    	int f1 = find(a), f2 = find(b);
    	if(f1 == f2)	return false;//无法合并 
    	 f[f1] = f2;	return true;//合并完返回 
    }
    void dfs(int now,int fa){
    	for(int i=head[now];i;i=line[i].nxt)
    		if(line[i].point!=fa)//遍历整颗生成树 
    		{
    			dfs(line[i].point,now);//向下递归解决子问题 
    			if(deg[line[i].point])	deg[now]^=1,ans=(ans+line[i].weight)%mod;//如果儿子的度数为奇数,我们就补一条,然后自己的度数++ 
    		}
    	return ;
    }
    int main(){
    	int now = 1,a,b,n,m;
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= n;i ++)	f[i] = i ;//并查集初始化 
    	for(int i = 1; i <= m;i ++)
    	{
    		scanf("%d%d",&a,&b);
    		now <<= 1;//now为边权 
    		now = now % mod;
    		ans = (ans + now) % mod ;//先将每条边都算一遍 
    		if(_union(a,b))	add(a, b, now), add(b, a, now) ;//因为边权是有序的,所以可以直接跑 
    		deg[a]^=1, deg[b]^=1;//度数问题我们只用关心奇偶就可以了 
    	}
    	dfs(1, 0) ;//其实从哪遍历都一样。 
    	printf("%d", ans) ;//输出 
    }
    

    T2

    (mathcal{color{red}{Description}})

    Ps:前不久因为我太颓了……所以这个就鸽了……ORZ我慢慢更……有些题不会我还要现学啊

  • 相关阅读:
    设计模式
    LiggEasyWinApp-104-Ligg.EasyWinForm:Zone
    Ligg.EasyWinApp-10300-Ligg.EasyWinForm:View的配置
    LiggEasyWinApp-103-Ligg.EasyWinForm:View
    Ligg.EasyWinApp-102-Ligg.EasyWinForm:Function--ControlBox、Tray、Resize、Menu
    Ligg.EasyWinApp-101-Ligg.EasyWinForm: Application--启动,传入参数、读取Application级别配置文件、验证密码、软件封面、启动登录、StartForm
    Ligg.EasyWinApp-100-Ligg.EasyWinForm:一款Winform应用编程框架和UI库介绍
    Ligg.WinOa-000: Windows运维自动化编程实战--前言
    Ligg.EasyWinApp-000: 一款Windows应用编程框架介绍
    微服务分布式 spring cloud springboot 框架源码 activiti工作流 前后分离
  • 原文地址:https://www.cnblogs.com/pks-t/p/9175951.html
Copyright © 2011-2022 走看看