Codeforces Round #529 (Div. 3)

A. Repeating Cipher

Polycarp loves ciphers. He has invented his own cipher called repeating.
Repeating cipher is used for strings. To encrypt the string s=s1s2sm(1m101m10)s=s_1s_2…s_m(1≤m≤101≤m≤10), Polycarp uses the following algorithm:

  • he writes down s1s_1 ones,
  • he writes down s2s_2 twice,
  • he writes down s3s_3 three times,
  • he writes down sms_m m times.

For example, if s=“bab” the process is: “b” → “baa” → “baabbb”. So the encrypted s=“bab” is “baabbb”.
Given string t — the result of encryption of some string s. Your task is to decrypt it, i. e. find the string s.
Input
The first line contains integer n (1≤n≤55) — the length of the encrypted string. The second line of the input contains t — the result of encryption of some string s. It contains only lowercase Latin letters. The length of t is exactly n.
It is guaranteed that the answer to the test exists.
Output
Print such string s that after encryption it equals t.

code

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	char s[1000];
	int n;
	scanf("%d%s", &n, s);
	for(int i = 0, j = 1; i < n; i+=j, j++){
		printf("%c", s[i]);
	}
	printf("\n");
	return 0;
} 

B. Array Stabilization

You are given an array a consisting of n integer numbers.
Let instability of the array be the following value:maxi=1naimini=1naimax_{i=1}^{n} a_i- min_{i=1}^{n}a_i
You have to remove exactly one element from this array to minimize instability of the resulting (n−1)-elements array. Your task is to calculate the minimum possible instability.
Input
The first line of the input contains one integer n(2n105)n (2≤n≤10^5) — the number of elements in the array a.
The second line of the input contains n integers a1,a2,,an(1ai105)a_1,a_2,…,a_n (1≤a_i≤10^5) — elements of the array a.
Output
Print one integer — the minimum possible instability of the array if you have to remove exactly one element from the array a.

题意:求长度为n的数组去掉一个元素后该数组最大值与最小值的最小差。
code

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e5+10;
int w[maxn];
int main(){
	int n;
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &w[i]);
	sort(w, w+n);
	printf("%d\n", min(w[n-1]-w[1], w[n-2]-w[0]));
	return 0;
} 

C. Powers Of Two

A positive integer x is called a power of two if it can be represented as x=2yx=2^y, where y is a non-negative integer. So, the powers of two are 1,2,4,8,16,…
You are given two positive integers n and k. Your task is to represent n as the sum of exactly k powers of two.
Input
The only line of the input contains two integers n and k (1n109,1k2105)(1≤n≤10^9, 1≤k≤2⋅10^5).
Output
If it is impossible to represent n as the sum of k powers of two, print NO.
Otherwise, print YES, and then print k positive integers b1,b2,,bkb_1,b_2,…,b_k such that each of bi is a power of two, and i=1kbi=n∑_{i=1}^kb_i=n. If there are multiple answers, you may print any of them.

题意:给定n和k,求n能否被分成k个2的*次幂数(1,2,4,8…)
题解:计算n二进制中1的个数cnt,若k < cnt || k > n则无解;反之有解
code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int w[33];
int main(){
	memset(w, 0, sizeof(w));
	int n, k;
	scanf("%d%d", &n, &k);
	int cnt = 0, t = n;
	for(int i = 0; t; i++){
		if(t & 1){
			cnt++;
			w[i]+=1;
		} 
		t>>=1;
	}
	if(cnt > k || n < k) printf("NO\n");
	else{
		printf("YES\n");
		int f = k-cnt;
		for(int i = 32; f && i > 0; i--){
			while(w[i] && f){
				w[i]-=1;
				w[i-1]+=2;
				f--;
			}
		}
		for(int i = 0; i <= 32; i++){
			int ans = 1;
			for(int j = 0; j < i; j++) ans*=2;
			for(int j = 0; j < w[i]; j++){
				printf("%d ", ans);
			}
		}
		printf("\n");
	}
	return 0;
} 

D. Circular Dance

There are n kids, numbered from 1 to n, dancing in a circle around the Christmas tree. Let’s enumerate them in a clockwise direction as p1,p2,...,pnp_1, p_2, ..., p_n(all these numbers are from 1 to n and are distinct, so p is a permutation). Let the next kid for a kid pip_i be kid pi+1p_{i+1} if i&lt;ni&lt;n and p1p_1 otherwise. After the dance, each kid remembered two kids: the next kid (let’s call him x) and the next kid for x. Each kid told you which kids he/she remembered: the kid i remembered kids ai,1a_{i,1} and ai,2a_{i,2}. However, the order of ai,1a_{i,1} and ai,2a_{i,2} can differ from their order in the circle.
Example: 5 kids in a circle, p=[3,2,4,1,5] (or any cyclic shift). The information kids remembered is: a1,1=3,a1,2=5;a2,1=1,a2,2=4;a3,1=2,a3,2=4;a4,1=1,a4,2=5;a5,1=2,a5,2=3a_{1,1}=3, a_{1,2}=5; a_{2,1}=1, a_{2,2}=4; a_{3,1}=2, a_{3,2}=4; a_{4,1}=1, a_{4,2}=5; a_{5,1}=2, a_{5,2}=3.
You have to restore the order of the kids in the circle using this information. If there are several answers, you may print any. It is guaranteed that at least one solution exists.
If you are Python programmer, consider using Py instead of Python when you submit your code.
Input
The first line of the input contains one integer n (3n2105)(3≤n≤2⋅10^5) — the number of the kids.
The next n lines contain 2 integers each. The i-th line contains two integers ai,1a_{i,1} and ai,2a_{i,2} (1ai,1,ai,2n,ai,1ai,2)(1≤a_{i,1},a_{i,2}≤n,a_{i,1}≠a_{i,2}) — the kids the i-th kid remembered, given in arbitrary order.
Output
Print n integers p1,p2,...,pnp_1, p_2, ..., p_n — permutation of integers from 1 to n, which corresponds to the order of kids in the circle. If there are several answers, you may print any (for example, it doesn’t matter which kid is the first in the circle). It is guaranteed that at least one solution exists.

题意:给出每一个结点的后两个结点,求结点序列
题解:特判当n=3时结果为1 2 3.
当n > 3时,对于所有结点viv_i的后两个结点vj,vkv_j, v_k中一定存在一个结点vjkv_{j || k}的后两个结点中存在另一个结点,且该结点为为viv_i的后一个结点。
- 即vi,1=vj,vi,2=vkv_{i, 1} = v_j , v_{i, 2} = v_k & (vj,=vkvk,=vj)(v_{j, *} = v_k || v_{k,*} = v_j)
code

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 2e5+10;
pair<int, int> p[maxn];
int w[maxn];
int main(){
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		int f1, f2;
		scanf("%d%d", &f1, &f2);
		p[i] = make_pair(f1, f2);
	}
	if(n == 3){
		printf("1 2 3\n");
		return 0;
	}
	for(int i = 1; i <= n; i++){
		int v = p[i].first;
		if(p[i].second == p[v].first || p[i].second == p[v].second){
			w[i] = v;
		}
		else{
			w[i] = p[i].second;
		}
	}
	int k = 1;
	for(int i = 1; i <= n; i++){
		i != n ? printf("%d ", k):printf("%d\n", k);
		k = w[k];
	}
	return 0;
} 

E. Almost Regular Bracket Sequence

You are given a bracket sequence s consisting of n opening ‘(’ and closing ‘)’ brackets.
A regular bracket sequence is a bracket sequence that can be transformed into a correct arithmetic expression by inserting characters ‘1’ and ‘+’ between the original characters of the sequence. For example, bracket sequences “()()”, “(())” are regular (the resulting expressions are: “(1)+(1)”, “((1+1)+1)”), and “)(” and “(” are not.
You can change the type of some bracket si. It means that if si= ‘)’ then you can change it to ‘(’ and vice versa.
Your task is to calculate the number of positions ii such that if you change the type of the i-th bracket, then the resulting bracket sequence becomes regular.
Input
The first line of the input contains one integer n (1n106)(1≤n≤10^6) — the length of the bracket sequence.
The second line of the input contains the string s consisting of n opening ‘(’ and closing ‘)’ brackets.
Output
Print one integer — the number of positions ii such that if you change the type of the ii-th bracket, then the resulting bracket sequence becomes regular.

题意:括号序列中只更换一个符号能使得括号序列变为常规序列的操作有多少种
code

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1e6+10;
char st[maxn];
char s[maxn];
int main(){
	int n, k = 0, ans = 0;
	scanf("%d%s", &n, s);
	for(int i = 0; i < n; i++){
		if(k == 0){
			st[k++] = s[i];
		}
		else{
			if(s[i] == ')' && st[k-1] == '(') k-=1;
			else st[k++] = s[i];
		}
	}
	if(k!=2 || (st[0]==')' && st[1]=='(')){
		printf("0\n");
		return 0;
	}
	else if(st[0] == '('){
		for(int i = 0, j = n-1; i < n/2; i++, j--){
			if(s[i] == '(') s[i] = ')';
			else s[i] = '(';
			if(s[j] == '(') s[j] = ')';
			else s[j] = '(';
			swap(s[i], s[j]);
		}
	}
	k = 0;
	for(int i = 0; i < n; i++){
		if(k == 0){
			st[k++] = s[i];
			if(s[i] == ')'){
				ans+=1;
				break;
			}
		}
		else{
			if(s[i] == ')' && st[k-1]=='(')
				k-=1;
			else
				st[k++] = s[i];
			if(s[i]==')') ans++;
		}
	}
	printf("%d\n", ans);
	return 0;
}

F. Make It Connected

You are given an undirected graph consisting of n vertices. A number is written on each vertex; the number on vertex i is aia_i. Initially there are no edges in the graph.
You may add some edges to this graph, but you have to pay for them. The cost of adding an edge between vertices x and y is ax+aya_x+a_y coins. There are also mm special offers, each of them is denoted by three numbers x, y and w, and means that you can add an edge connecting vertices x and y and pay w coins for it. You don’t have to use special offers: if there is a pair of vertices x and y that has a special offer associated with it, you still may connect these two vertices paying ax+aya_x+a_y coins for it.
What is the minimum number of coins you have to spend to make the graph connected? Recall that a graph is connected if it’s possible to get from any vertex to any other vertex using only the edges belonging to this graph.
Input
The first line contains two integers n and m (1n2105,0m2105)(1≤n≤2⋅10^5, 0≤m≤2⋅10^5) — the number of vertices in the graph and the number of special offers, respectively.
The second line contains n integers a1,a2,,an(1ai1012)a_1,a_2,…,a_n (1≤ai≤10^{12}) — the numbers written on the vertices.
Then m lines follow, each containing three integers x, y and w (1x,yn,1w1012,xy)(1≤x,y≤n, 1≤w≤10^{12}, x≠y) denoting a special offer: you may add an edge connecting vertex x and vertex y, and this edge will cost w coins.
Output
Print one integer — the minimum number of coins you have to pay to make the graph connected.

题意:每个顶点有一个aia_i,若想在两个顶点连接一条无向边需要消耗ax+aya_x+a_y,另外给出一些特殊无向边使两顶点连接仅需消耗wiw_i。问要让所有顶点形成一个无向联通图需要消耗多少。
题解:=最小生成树消耗费用,求出最小的ava_v使其与其他顶点建立新边套Kruskal算法。
code

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e5+10;
const long long INF = 0x3f3f3f3f3f3f3f3f;
typedef struct node
{
    int pre, suc;
	long long w;
    bool operator < (const node & A) const
    {
        return w < A.w;
    }
}Edge; //每条边的起始、终止和权重
 
Edge edge[maxn<<1]; //记录每条边
int pre[maxn] = {0}; //记录每个顶点的上级
long long w[maxn];
void make_set(int n) //初始化并查集
{
    for (int i = 1; i <= n; ++i)
        pre[i] = i;
}
 
 
int find_root(int x) //非递归找x的根节点
{
    int r = x;
    while (pre[r] != r)
        r = pre[r];
    //路径压缩
    int i = x, j;
    while (i != r)
    {
        j = pre[i];
        pre[i] = r;
        i = j;
    }
    return r;
}
 
long long kruskal(int n, int num) //n顶点数, num边数
{
    sort(edge, edge+num); //按权重升序,注意是边数
    make_set(n); //并查集初始化
    int fx, fy;
    long long sum = 0;
    for (int i = 0; i < num; ++i)
    {
        fx = find_root(edge[i].pre);
        fy = find_root(edge[i].suc);
        if (fx != fy) //如果不连通
        {
            pre[fy] = fx;
            sum += edge[i].w; //将这条边加入
        }
    }
    return sum;
}
 
int main()
{
    ios::sync_with_stdio(false);
    int n, m, k;
    long long ans;
    scanf("%d%d", &n, &m);
    long long Min = INF;
	for(int i = 1; i <= n; i++){
		scanf("%lld", &w[i]);
		if(Min > w[i]){
			Min = w[i], k = i;
		}
	}
    for (int i = 0; i < m; ++i)
        scanf("%d%d%lld", &edge[i].pre,&edge[i].suc,&edge[i].w);
    for(int i = 1; i <= n; i++){
		if(i!=k){
			edge[m+i-1].pre = k;
			edge[m+i-1].suc = i;
			edge[m+i-1].w = w[i]+w[k];
		}
	}
    ans = kruskal(n, m+n);
    printf("%lld", ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章