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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章