Codeforces Round #624 (Div. 3) 解(补)题报告

前言

由于我熬夜的时候解题效率很差,因此在决定开始打CF之后,尽量在比赛后的第二天拉一套题在VJ上面做,就当成练习题做,因为比赛的话自己水平还比较低,先多做Div3,这个比赛是我第一次做div3,做了三道,补了两道(比较菜的那种)E题待补

A - Add Odd or Subtract Even (签到)

You are given two positive integers a and b.In one move, you can change a in the following way:Choose any positive odd integer x (x>0) and replace a with a+x;choose any positive even integer y (y>0) and replace a with a−y.You can perform as many such operations as you want. You can choose the same numbers x and y in different moves.Your task is to find the minimum number of moves required to obtain b from a. It is guaranteed that you can always obtain b from a.You have to answer t independent test cases.

Input
The first line of the input contains one integer t (1≤t≤104) — the number of test cases.Then t test cases follow. Each test case is given as two space-separated integers a and b (1≤a,b≤109).

Output
For each test case, print the answer — the minimum number of moves required to obtain b from a if you can perform any number of moves described in the problem statement. It is guaranteed that you can always obtain b from a.

1.题目大意:给出两个数a,b,每次可以对a或b加减任意数,求最少多少步可以使a,b相等

2.直接模拟即可,我们发现,先求出二者的差值,那么再分别对其正负情况考虑是奇偶性。最多两步就能得到答案

代码:

#include <iostream>
#include <math.h>
using namespace std;

int a,b,t;

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&a,&b);
        int c=b-a;
        if(c>0){
            if(c&1) printf("1\n");
            else printf("2\n");
        }else if(c<0){
            c=abs(c);
            if(c&1) printf("2\n");
            else printf("1\n");
        }else printf("0\n");
    }
    return 0;
}

B - WeirdSort (BFS)

You are given an array a of length n.You are also given a set of distinct positions p1,p2,…,pm, where 1≤pi<n. The position pi means that you can swap elements a[pi] and a[pi+1]. You can apply this operation any number of times for each of the given positions.Your task is to determine if it is possible to sort the initial array in non-decreasing order (a1≤a2≤⋯≤an) using only allowed swaps.For example, if a=[3,2,1] and p=[1,2], then we can first swap elements a[2] and a[3] (because position 2 is contained in the given set p). We get the array a=[3,1,2]. Then we swap a[1] and a[2] (position 1 is also contained in p). We get the array a=[1,3,2]. Finally, we swap a[2] and a[3] again and get the array a=[1,2,3], sorted in non-decreasing order.You can see that if a=[4,1,2,3] and p=[3,2] then you cannot sort the array.You have to answer t independent test cases.

Input
The first line of the input contains one integer t (1≤t≤100) — the number of test cases.Then t test cases follow. The first line of each test case contains two integers n and m (1≤m<n≤100) — the number of elements in a and the number of elements in p. The second line of the test case contains n integers a1,a2,…,an (1≤ai≤100). The third line of the test case contains m integers p1,p2,…,pm (1≤pi<n, all pi are distinct) — the set of positions described in the problem statement.

Output
For each test case, print the answer — “YES” (without quotes) if you can sort the initial array in non-decreasing order (a1≤a2≤⋯≤an) using only allowed swaps. Otherwise, print “NO”.

1.题目大意,给出一个大小为n的1-n的序列a,再给出一个数组p,p数组的每个数代表p的下标,意思是a数组下标p和p+1可以交换位置。求在指定交换序列下,a数组能否变为升序

2.如果a序列变为升序,那么每一个元素的后继一定比它大1,这里我想的是BFS,每一次将所有不符合的节点入队,接下来一次性把入队的节点都按照条件交换,然后判断是否升序成功。当队列空了如果还没成功就代表无法得到

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int a[105],vis[105];
int t,n,m,x;
queue<int> q;

bool check(){
    int flag=1;
    for(int i=2;i<=n;i++)
        if(a[i]<a[i-1]){
            q.push(i);
            flag=0;
        }
    if(flag) return true;
    else return false;
}

bool bfs(){
    while(!q.empty()) q.pop();
    if(check()) return true;
    while(!q.empty()){
        int MAX=q.size(); //一定要一次性操作完上一次入队的所有节点
        while(MAX--){
            int u=q.front();q.pop();
            if(!vis[u-1]) return false;
            swap(a[u-1],a[u]);
        }
        if(check()) return true;
    }
    return true;
}

int main()
{
    scanf("%d",&t);
    while(t--){
        memset(vis,0,sizeof vis);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        while(m--){
            scanf("%d",&x);
            vis[x]=1;
        }
        if(bfs()) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

C - Perform the Combo (差分+树状数组)

You want to perform the combo on your opponent in one popular fighting game. The combo is the string s consisting of n lowercase Latin letters. To perform the combo, you have to press all buttons in the order they appear in s. I.e. if s=“abca” then you have to press ‘a’, then ‘b’, ‘c’ and ‘a’ again.You know that you will spend m wrong tries to perform the combo and during the i-th try you will make a mistake right after pi-th button (1≤pi<n) (i.e. you will press first pi buttons right and start performing the combo from the beginning). It is guaranteed that during the m+1-th try you press all buttons right and finally perform the combo.I.e. if s=“abca”, m=2 and p=[1,3] then the sequence of pressed buttons will be ‘a’ (here you’re making a mistake and start performing the combo from the beginning), ‘a’, ‘b’, ‘c’, (here you’re making a mistake and start performing the combo from the beginning), ‘a’ (note that at this point you will not perform the combo because of the mistake), ‘b’, ‘c’, ‘a’.Your task is to calculate for each button (letter) the number of times you’ll press it.You have to answer t independent test cases.

Input
The first line of the input contains one integer t (1≤t≤104) — the number of test cases.Then t test cases follow.The first line of each test case contains two integers n and m (2≤n≤2⋅105, 1≤m≤2⋅105) — the length of s and the number of tries correspondingly.The second line of each test case contains the string s consisting of n lowercase Latin letters.The third line of each test case contains m integers p1,p2,…,pm (1≤pi<n) — the number of characters pressed right during the i-th try.It is guaranteed that the sum of n and the sum of m both does not exceed 2⋅105 (∑n≤2⋅105, ∑m≤2⋅105).It is guaranteed that the answer for each letter does not exceed 2⋅109.

Output
For each test case, print the answer — 26 integers: the number of times you press the button ‘a’, the number of times you press the button ‘b’, …, the number of times you press the button ‘z’.

1.题目大意:给出一串字符(a-z),每次下面给出一个序列。从字符串的第一个节点开始按,每次按到序列的第i个元素,就返回第一个字母。当这个序列按完之后就额外从头按到尾,求在按的过程中所有字母出现的次数

2.对于序列a[i],实际上就是对字符串前a[i]个都按一次,即区间都加一,而且我们最后要求的是每个节点的次数,显然是树状数组。首先我们引入差分的概念:差分即相邻两个数的差,由a数组我们能得到a的差分数组d[i]=a[i]-a[i-1],还可以得到二者之间的关系:
a[i]=d[1]+…+d[i]
那么我们会发现,如果对一个区间[x,y]内的所有数都执行加法,那么显然只有d[x]和d[y+1]的值会改变,[x+1,y]区间的值都不变。因此我们用d数组维护树状数组,当我们进行区间加法时,很明显只用更新d[x]和d[y+1],即d[x]+k,d[y+1]-k

代码:

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
#define lowbit(x) (x&(-x))
const int maxn=2e5+10;
int a[maxn],t[maxn],ans[30];
int T,m,n,x;
string s;

void update(int i,int k){
    while(i<=n){
        t[i]+=k;
        i+=lowbit(i);
    }
}

int ask(int i){
    int ans=0;
    for(;i;i-=lowbit(i)){
        ans+=t[i];
    }
    return ans;
}

int main()
{
    scanf("%d",&T);
    while(T--){
        memset(t,0,sizeof t);
        memset(ans,0,sizeof ans);
        scanf("%d%d",&n,&m);
        cin>>s;
        for(int i=0;i<s.size();i++){
            a[i+1]=s[i]-'a';
        }
        while(m--){
            scanf("%d",&x);
            update(1,1);
            update(x+1,-1);
        }
        update(1,1);
        update(n+1,-1);
        for(int i=1;i<=n;i++){
            ans[a[i]]+=ask(i);
        }
        for(int i=0;i<26;i++){
            printf("%d%c",ans[i],i==25?'\n':' ');
        }
    }
    return 0;
}

D - Three Integers (枚举)

https://blog.csdn.net/qq_44691917/article/details/104539224

E - Construct the Binary Tree (思维)

题目链接

You are given two integers n and d. You need to construct a rooted binary tree consisting of n vertices with a root at the vertex 1 and the sum of depths of all vertices equals to d.A tree is a connected graph without cycles. A rooted tree has a special vertex called the root. A parent of a vertex v is the last different from v vertex on the path from the root to the vertex v. The depth of the vertex v is the length of the path from the root to the vertex v. Children of vertex v are all vertices for which v is the parent. The binary tree is such a tree that no vertex has more than 2 children.You have to answer t independent test cases.

Input
The first line of the input contains one integer t (1≤t≤1000) — the number of test cases.The only line of each test case contains two integers n and d (2≤n,d≤5000) — the number of vertices in the tree and the required sum of depths of all vertices.It is guaranteed that the sum of n and the sum of d both does not exceed 5000 (∑n≤5000,∑d≤5000).

Output
For each test case, print the answer.If it is impossible to construct such a tree, print “NO” (without quotes) in the first line. Otherwise, print “{YES}” in the first line. Then print n−1 integers p2,p3,…,pn in the second line, where pi is the parent of the vertex i. Note that the sequence of parents you print should describe some binary tree.

1.题目大意:给出节点个数去构造二叉树,求是否能构造出深度和为d的二叉树。刚开始我写的是剪枝+搜索,结果超时了,原来是我没怎么计算时间复杂度,5000个节点即使剪枝也会超时的,如果有几百个节点可以试一下爆搜

2.看别人思路,原来是这样:链状的二叉树总深度一定是最大的,然后完全二叉树总深度是最小的,那么我们就先假设构成一条链,看看能否一步步移动节点构成需要的二叉树。首先每层节点选择一个代表并标记,然后从大到小将未标记的节点作为本层代表的子节点,若当层代表还有其他子节点,继续下移。直到移动到最后一层后自己作为新一层的代表并标记即可

3.代码不太好写,下面别人的代码还不是很懂,等以后再研究研究(最近事情好多)

#include<bits/stdc++.h>
using namespace std;
const int N=5005+5;
int t,n,m,l,r,sum[N],dep[N];

bool solve(){
	fill(dep+1,dep+n+1,1);
	m=n*(n-1)/2-m;
	for(l=2,r=n;l<r;r--){
		while(l<r && (m-r+l<0 || dep[l]==dep[l-1]*2)) l++;
		if(l>=r) break;
		m-=r,dep[r]--;
		m+=l,dep[l]++;
	}
	return m==0;
}

int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		if(!solve()) printf("NO\n");
		else{
			printf("YES\n");
			for(int i=1;i<=r;++i)
			sum[i]=sum[i-1]+dep[i];
			for(int i=2;i<=r;++i){
				for(int j=0;j<dep[i];++j)
				printf("%d ",sum[i-2]+1+j/2);
			}
			printf("\n");
		}
	}
	return 0;
}

/*     剪枝搜索超时了
#include <iostream>
using namespace std;
int t,n,m;
int tot;
int a[5005];

bool dfs(int cur,int num,int ans,int maxn){  //cur表示当前第几层,num表示上一层传下来几个数,ans表示当前层数总和,maxn表示当前一共用了几个数字
    if(maxn==n && ans==m) return true;
    else if(ans>m || maxn>n) return false;
    if((2*cur+n-maxn)*(n-maxn)/2+ans<n) return false;
    int MAX=2*num;
    int p=maxn-num+1;
    for(int i=1;i<=MAX;i++){
        if(i&1) a[maxn+i]=p;
        else a[maxn+i]=p++;
        if(dfs(cur+1,i,ans+cur*i,maxn+i)) return true;
    }
    return false;
}

void solve(){
    for(int i=2;i<=n;i++)
        printf("%d%c",a[i],i==n?'\n':' ');
}

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        tot=1;
        if(m>n*(n-1)/2){
            printf("NO\n");
            continue;
        }
        if(dfs(1,1,0,1)){
            printf("YES\n");
            solve();
        }else printf("NO\n");
    }
    return 0;
}*/

F - Moving Points (树状数组+离散化)

https://blog.csdn.net/qq_44691917/article/details/104539711

发布了128 篇原创文章 · 获赞 7 · 访问量 5273

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/104541280