cf div2 #453 ABC(D)

赛中只搞出ABC,C想的还有点久,没时间搞D了(虽然是推了很久都没推出来),蒟蒻的上分之旅。


A. Visiting a Friend

题意:

你的初始位置为0,给你n和m,m表示你的目的地,n表示可乘坐工具的个数。接下来n行,每行一个x y,表示在位置x处有一个工具,你可以坐着它到位置y(你可以中途跳车,比如样例1中,0->2,2->4,在2->4过程中跳车,在位置3坐上3->5,可以抵达m=5的位置)。问你能不能用这个工具到达m。


思路:

保证n组工具覆盖的长度是0-m即可。

贪心:把工具存结构体然后排个序,按x从小到大和y从小到大排好,初始化当前位置为0,遍历工具,考虑:如果当前位置大于等于工具的

x,就把当前位置赋值成y,否则肯定无法到达当前x处,即无法借助这种工具到达m。


AC代码:

/**********************************************
	Author:		StupidTurtle
	Date:		2017.12.19
	Email:		[email protected]
**********************************************/

#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll ;

int n , m , ans ;

struct node{
	int x , y ;
};

node a[105] ;

bool cmp ( const node &a , const node &b ){
	if ( a.x != b.x )	return a.x < b.x ;
	return a.y < b.y ;
}

int main(void){
	
	ans = 0 ;
	cin >> n >> m ;
	for ( int i = 0 ; i < n ; i ++ ){
		cin >> a[i].x >> a[i].y ;
	}
	sort ( a , a + n , cmp );
	for ( int i = 0 ; i < n ; i ++ ){
		if ( a[i].x <= ans ){
			ans = max ( ans , a[i].y );
		} else {
			break ;
		}
	}
	if ( ans == m )	cout << "YES" << endl ;
	else	cout << "NO" << endl ;
	
	return 0 ;
}

B. Coloring a Tree

题意:

第一行给你一个n,表示n个点;第二行输入n-1个数字,p2,p3,...,pn,分别表示pi的父节点(认为1是树的根);第三行输入n个数字,表示c1,c2,...,cn,表示ci节点想被染上的颜色,c1,c2,...,cn,初值均为0。将某个点染色后,它的子树也会变成和它一样的颜色。问将整棵树染成目标颜色的树最少需要多少步。


思路:

因为对一个节点染色会影响其子树,所以先染根节点再向下染色。

dfs:因为ci是[1,n]而c1初值为0,所以根节点必被染色,所以初始化cnt为1,dfs的带两个参数,分别为当前点下标和父节点的颜色,如果父节点颜色和当前点的目标颜色不同,则cnt++,遍历每个子节点。


AC代码:

/**********************************************
	Author:		StupidTurtle
	Date:		2017.12.19
	Email:		[email protected]
**********************************************/

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll ;

int n , prt , ex[10005] , cnt ;
vector<int> tree[10005] ;

void dfs ( int v0 , int col ){
	if ( ex[v0] != col ){
		cnt ++ ;
	}
	int l = tree[v0].size() ;
	for ( int i = 0 ; i < l ; i ++ ){
		dfs ( tree[v0][i] , ex[v0] );
	}
}

int main(void){
	
	cin >> n ;
	for ( int i = 2 ; i <= n ; i ++ ){
		cin >> prt ;
		tree[prt].push_back(i) ;
	}
	for ( int i = 1 ; i <= n ; i ++ ){
		cin >> ex[i] ;
	}
	cnt = 1 ;
	dfs ( 1 , ex[1] );
	cout << cnt << endl ;
	
	return 0 ;
}

C. Hashing Trees

题意:

给你一个n,表示一颗树的高度,第二行n+1个数,分别表示树的第0层,第1层,...,第n层有多少个节点,问你这样的树是否存在两颗不同构的,如果没有则输出"perfect",否则输出"ambiguous",然后接下来两行其中的任意两颗。

(同构:两棵树如果可以通过交换子树可以变成一样的,则这两棵树同构。)


思路:

做过B题之后做这道题可以注意道:这道题对树的描述也仅仅是一颗有根树且根为1,并不是一颗二叉树(可以从B题的Sample2看出),那我们要思考的就是对于一颗非二叉树,怎么样做到让他唯一。由Sample1想到,如果全是1则必定perfect。在Sample2中1 2 2可以得到两棵非同构的树,那么如果是1 2 1呢?第2层的一个结点可以挂在第1层的任意一个子结点上,所以也是perfect的。由此推广:只要没有连续两个非1的节点数,则该树是perfect的。接下来考虑输出问题,只要输出其中一对就可以了,所以在第一次出现连续非1的层数时,在第一颗树中将后一层的一个挂在前一层的第一个节点上,其余的挂在前一层的第二个结点上,在第二颗树中将后一层的所有节点都挂在前一层的第一个节点上。对于其他情况,直接将后一层的节点全都挂在前一层的第一个节点上即可。


AC代码:

/**********************************************
	Author:		StupidTurtle
	Date:		2017.12.19
	Email:		[email protected]
**********************************************/

#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll ;

int n , a[200005] , crt , cnt , l , pf ;
bool flag , first ;

int main(void){
	
	flag = true ;
	cin >> n ;
	for ( int i = 0 ; i <= n ; i ++ ){
		cin >> a[i] ;
	}
	crt = a[0] ;
	for ( int i = 1 ; i <= n ; i ++ ){
		if ( a[i] != 1 && crt != 1 ){
			flag = false ;
			break ;
		} else {
			crt = a[i] ;
		}
	}
	if ( flag == true ){
		cout << "perfect" << endl ;
	} else {
		cout << "ambiguous" << endl ;
		first = false ;
		cout << "0" ;
		crt = a[0] ;
		l = 1 ;
		cnt = 1 ;
		for ( int i = 1 ; i <= n ; i ++ ){
			pf = l ;
			if ( crt != 1 && a[i] != 1 ){
				if ( first == false ){
					for ( int j = 0 ; j < a[i] ; j ++ ){
						cnt ++ ;
						if ( j == 0 ){
							cout << " " << pf ;
							l = cnt ;
						}
						else	cout << " " << pf+1 ;
					}
					flag = true ;
				} else {
					for ( int j = 0 ; j < a[i] ; j ++ ){
						cout << " " << pf ;
						cnt ++ ;
						if ( j == 0 )	l = cnt ;
					}
				}
			} else {
				for ( int j = 0 ; j < a[i] ; j ++ ){
					cout << " " << pf ;
					cnt ++ ;
					if ( j == 0 )	l = cnt ;
				}
				crt = a[i] ;
			}
		}
		cout << endl ;
		
		cout << "0" ;
		crt = a[0] ;
		l = 1 ;
		cnt = 1 ;
		for ( int i = 1 ; i <= n ; i ++ ){
			pf = l ;
			for ( int j = 0 ; j < a[i] ; j ++ ){
				cout << " " << pf ;
				cnt ++ ;
				if ( j == 0 )	l = cnt ;
			}
			crt = a[i] ;
		}
		cout << endl ;
	}
	
	return 0 ;
}

D. GCD of Polynomials

题意:

规定A(X),B(X),R(X),D(X)分别是一个多项式,定义A(X)=B(X)*D(X)+R(X),且R(X)的最高次的次数要比B(X)的最高次的次数要小。这样子定义出GCD(A(X),B(X)) = R(X)。这个描述定义了多项式的gcd。然后输入一个n,表示进行n次gcd(A(X),B(X))后B(X)的结果为0。要求分四行输出进行第一次gcd(A(X),B(X))之前:A(X)的最高次的次数;次数由低到高输出A(X)每一项的系数;B(X)的最高次的次数;次数由低到高输出B(X)每一项的系数。


思路:

赛中没有想到,赛后得知:如果进行第n次gcd的结果是A(X),B(X),那么进行第n-1次的结果就是A(X)*X±B(X),A(X)。尝试多推几项:

0----------------1----------------0

1----------------x----------------1

2-------------x^2+1------------x

3--------------x^3------------x^2+1

4---------x^4+x^2+1---------x^3

转换成二进制后的结果:

0--------------000001------------000000

1--------------000010------------000001

2--------------000101------------000010

3--------------001000------------000101

4--------------010101------------001000

可以发现从第一行开始,每一行的B(X)变成了上一行的A(x)(显而易见),而每一行的A(X)变成了这一行的B(X)左移一位后再异或上一行的B(X)。

由于n是[1,150],1<<150在C++存不下(我用int在Sample31TLE,用longlong在Sample63TLE),所以在我的方法下用了java


AC代码:

import java.util.Scanner ;
import java.math.* ;

public class Main {
	public static void main ( String[] args ) {
		Scanner cin = new Scanner(System.in);
		
		int n = cin.nextInt() ;
		BigInteger l = BigInteger.valueOf(1) , r = BigInteger.valueOf(0) , mid ;
		for ( int i = 2 ; i <= n + 1 ; i ++ ) {
			mid = r ;
			r = l ;
			l = l.shiftLeft(1) ;
			l = l.xor(mid) ;
		}
		System.out.println( n );
		for ( int i = 0 ; i < n + 1 ; i ++ ) {
			if ( i != 0 )	System.out.print( " " );
			System.out.print( l.and(BigInteger.valueOf(1) ) );
			l = l.shiftRight(1) ;
		}
		System.out.println( );
		System.out.println( n - 1 );
		for ( int i = 0 ; i < n ; i ++ ) {
			if ( i != 0 )	System.out.print( " " );
			System.out.print( r.and(BigInteger.valueOf(1) ) );
			r = r.shiftRight(1) ;
		}
		System.out.println( );
	}
}


猜你喜欢

转载自blog.csdn.net/stupid_turtle/article/details/78850180