zoukankan      html  css  js  c++  java
  • test20190731 夏令营NOIP训练16

    0+90+0=90。我只挑了T2做。

    连接格点

    有一个M行N列的点阵,相邻两点可以相连。一条纵向的连线花费一个单位,一条横向的连线花费两个单位。某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。

    输入格式:
    第一行输入两个正整数m和n。
    以下若干行每行四个正整数x1,y1,x2,y2,表示第x1行第y1列的点和第x2行第y2列的点已经有连线。输入保证|x1-x2|+|y1-y2|=1。

    输出格式:
    输出使得连通所有点还需要的最小花费。

    样例输入:
    2 2
    1 1 2 1

    样例输出:
    3

    数据范围:
    m,n<=1000

    时间限制:
    1000
    空间限制:
    32768

    最小生成树,而且不用排序了。

    无序字母对

    给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。

    输入格式:
    第一行输入一个正整数n。
    以下n行每行两个字母,表示这两个字母需要相邻。

    输出格式:
    输出满足要求的字符串。
    如果没有满足要求的字符串,请输出“No Solution”。
    如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案

    样例输入:
    4
    aZ
    tZ
    Xt
    aX

    样例输出:
    XaZtX

    数据范围:
    不同的无序字母对个数有限,n的规模可以通过计算得到。

    时间限制:
    1000
    空间限制:
    32768

    题解

    题意很清晰了,显然是求字典序最小的欧拉回路方案,但是我都忘了欧拉回路这回事。

    手动模拟

    发现合法情况一定是度数为奇数的点的个数为0或2。如果是0那就找最小的,如果是2那就找度数为奇数的最小的。

    然后发现中间合并两个无序对,度数的变化是偶数2,所以一定有解。然后用set维护找字典序最小的即可。

    但是交到洛谷1341发现WA了。然后看数据,发现了这种情况:

    5
    ax
    xx
    xt
    tp
    ps

    也就是自环。在ax的时候x优先选择走t,但是之后就走不到x了。

    所以在选择字典序较小的之前还要判断x下一个是否必须走到自己。这个就把其他点连回x的边数考虑一下就好了,把x放到后面边数至少为3。

    最后还是有一个点莫名RE,而学军中学的数据好像是一样的,所以这题就是90分了。

    #include<bits/stdc++.h>
    #define co const
    #define il inline
    template<class T> T read(){
    	T x=0,w=1;char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*w;
    }
    template<class T>il T read(T&x){
    	return x=read<T>();
    }
    using namespace std;
    
    co int N=52;
    il int idx(char c){
    	return islower(c)?26+c-'a':c-'A';
    }
    il char inv(int i){
    	return i<26?i+'A':i-26+'a';
    }
    
    int n,c[N];
    multiset<int> s[N];
    multiset<int>::iterator it;
    int main(){
    	read(n);
    	for(int i=1;i<=n;++i){
    		char p[3];scanf("%s",p);
    		++c[p[0]=idx(p[0])],++c[p[1]=idx(p[1])];
    		s[p[0]].insert(p[1]),s[p[1]].insert(p[0]);
    	}
    	int cnt=0;
    	for(int i=0;i<N;++i)
    		if(c[i]&1) ++cnt;
    	if(cnt!=0&&cnt!=2) return puts("No Solution"),0;
    	char ans[3000];
    	if(cnt==0){
    		for(int i=0;i<N;++i)
    			if(c[i]>=2){ans[0]=i,c[i]-=1;break;}
    	}
    	else{
    		for(int i=0;i<N;++i)
    			if(c[i]&1){ans[0]=i,c[i]-=1;break;}
    	}
    	for(int i=1;i<=n;++i){
    		if(s[ans[i-1]].count(ans[i-1])){ // edit 1
    			int cnt=0;
    			for(int j=0;j<N;++j)if(j!=ans[i-1])
    				cnt+=s[j].count(ans[i-1]);
    			if(cnt<3){
    				ans[i]=ans[i-1],c[ans[i]]-=2;
    				s[ans[i]].erase(s[ans[i]].find(ans[i])),s[ans[i]].erase(s[ans[i]].find(ans[i]));;
    				continue;
    			}
    		}
    		int cnt=0;
    		it=s[ans[i-1]].begin();
    		if(i<n&&c[*it]==1) ++it;
    		ans[i]=*it,c[ans[i]]-=2; // i==n doesn't matter
    		s[ans[i-1]].erase(s[ans[i-1]].find(ans[i])),s[ans[i]].erase(s[ans[i]].find(ans[i-1]));
    	}
    	for(int i=0;i<=n;++i) ans[i]=inv(ans[i]);
    	ans[n+1]=0;
    	puts(ans);
    	return 0;
    }
    /*
    5
    ax
    xx
    xt
    tp
    ps
    */
    

    欧拉回路

    欧拉回路算法直接就可以解决这个问题。

    欧拉回路是在回溯的时候把路径的答案加进去。这样在x之后如果能回来,先走的就是字典序较小的;如果不能,先走的就是x。

    感觉理解深入了不少。时间复杂度(O(n log n))

    数字转换

    如果一个数x的约数和(不包括它本身,下同)比它本身小,那么x可以变成它的约数和;如果对于某个y>x且y的约数和为x,那么x也可以变成y。例如,4可以变为3,1可以变为7。限定所有的数字变换在不超过n的正整数范围内进行,求不断进行数字变换且没有重复数字出现的最多变换步数。

    输入格式:
    输入一个正整数n。

    输出格式:
    输出最少需要花费的时间。

    样例输入:
    7

    样例输出:
    3

    数据范围:
    n<=50 000。

    时间限制:
    1000
    空间限制:
    32768

    题解

    只能向较小的连无向边,所以最后图一定是森林。

    然后跑树的直径就可以了。

    可以用来练习线性筛求约数和(误)。

    线性筛的第二重循环中要筛出来的数(x=i imes p_j)最小质因子一定是现在枚举的(p_j),此时分为两种情况:

    • (i)没有质因子(p_j),那么直接计算即可。
    • (i)有质因子(p_j),那么应该修改(p_j)的贡献。所以需要记录每个数的最小质因子对它的约数和的贡献。

    然后时间复杂度(O(n))

  • 相关阅读:
    django虚拟环境中报E: 无法定位软件包 sqliteman
    创建django项目
    Django虚拟环境安装
    python学习笔记(三)
    python学习笔记(二)
    python学习笔记(一)
    python 类属性和实例属性
    决策树的基本ID3算法
    KNN算法的简单实现
    webClient
  • 原文地址:https://www.cnblogs.com/autoint/p/11275585.html
Copyright © 2011-2022 走看看