7.6日训练赛 (刚进群,错过了。。)

A题上来一题就难死我了

You are given two bracket sequences (not necessarily regular) s and t consisting only of characters ‘(’ and ‘)’. You want to construct the shortest regular bracket sequence that contains both given bracket sequences as subsequences (not necessarily contiguous).

Recall what is the regular bracket sequence:

() is the regular bracket sequence;
if S is the regular bracket sequence, then (S) is a regular bracket sequence;
if S and T regular bracket sequences, then ST (concatenation of S and T) is a regular bracket sequence.
Recall that the subsequence of the string s is such string t that can be obtained from s by removing some (possibly, zero) amount of characters. For example, “coder”, “force”, “cf” and “cores” are subsequences of “codeforces”, but “fed” and “z” are not.

Input
The first line of the input contains one bracket sequence s consisting of no more than 200 characters ‘(’ and ‘)’.

The second line of the input contains one bracket sequence t consisting of no more than 200 characters ‘(’ and ‘)’.

Output
Print one line — the shortest regular bracket sequence that contains both given bracket sequences as subsequences (not necessarily contiguous). If there are several answers, you can print any.

Examples
Input
(())(()
()))()
Output
(())()()
Input
)
((
Output
(())
Input
)
)))
Output
((()))
Input
())
(()(()(()(
Output
(()()()(()()))
题意:输入两个括号序列 s,t,你需要构造一个尽可能短的合法括号序列使得s,t 都是这个序列的子序列,这里的是序列哦 不用连续!
思路:这个题看了题解 才知道需要用啥知识点,虽然还是不会做。设 dp[i][j][z] 表示已经 匹配到 序列 a 的第 i 位,序列 b 的第 j 位,当前左括号比右括号多 z 个的最短长度(规则序列,从左往右左括号当然只能比右括号多),
则最终答案是 dp[n][m][0] ( n=len(a) , m=len(b) ) – 转移状态:通过枚举左右括号
①: ( – 则 z+1,第 i , j 位若是 ‘(’ 加一,否则不加,dp[ii][jj][z+1]=dp[i][j][z]+1;
②: ) – 则 z -1,第 i , j 位若是 ‘)’ 加一,否则不加,dp[ii][jj][z- 1]=dp[i][j][z]+1;
注意要判断 z 的边界,因为要记录路径,所以,开个结构体同步更新就可以了

这种题感觉好难啊,感觉自己还是没掌握住/(ㄒoㄒ)/~~

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int maxn=210;
const int inf=0x3f3f3f3f;
int dp[maxn][maxn][maxn];
struct node{int x,y,z;char c;}st[maxn][maxn][maxn];
string s,t;
int sz,tz;
int nx,ny,nz;
inline void bfs(){
    sz=s.size(),tz=t.size();
    memset(dp,0x3f,sizeof dp);
    dp[0][0][0]=0;
    queue<node> q;q.push(node{0,0,0});
    while(!q.empty()){
        node tp=q.front();q.pop();
        //'('
        nx=tp.x+(tp.x<sz&&s[tp.x]=='(');
        ny=tp.y+(tp.y<tz&&t[tp.y]=='(');
        nz=tp.z+1;
        if(nz<=200&&dp[nx][ny][nz]==inf){
            dp[nx][ny][nz]=dp[tp.x][tp.y][tp.z]+1;
            q.push(node{nx,ny,nz});
            st[nx][ny][nz]=node{tp.x,tp.y,tp.z,'('};

        }
        
        //)
        nx=tp.x+(tp.x<sz&&s[tp.x]==')');
        ny=tp.y+(tp.y<tz&&t[tp.y]==')');
        nz=tp.z-1;
        if(nz>=0&&dp[nx][ny][nz]==inf){
            dp[nx][ny][nz]=dp[tp.x][tp.y][tp.z]+1;
            q.push(node{nx,ny,nz});
            st[nx][ny][nz]=node{tp.x,tp.y,tp.z,')'};
        }
    }
}

int main(){
    cin>>s>>t;
    bfs();

    string res="";
    int x=sz,y=tz,z=0;

    int px,py,pz;
    while(x||y||z){
        res+=st[x][y][z].c;
        px=st[x][y][z].x;
        py=st[x][y][z].y;
        pz=st[x][y][z].z;
        x=px,y=py,z=pz;
    }

    sz=res.size();
    for(int i=sz-1;i>=0;--i)cout<<res[i];
    cout<<endl;
    return 0;
}

这个题真的真的不容易 用到了好多的知识!自己没写出来,哎,还得加把劲啊

B题

You are given an array a consisting of n integers.

You can remove at most one element from this array. Thus, the final length of the array is n−1 or n.

Your task is to calculate the maximum possible length of the strictly increasing contiguous subarray of the remaining array.

Recall that the contiguous subarray a with indices from l to r is a[l…r]=al,al+1,…,ar. The subarray a[l…r] is called strictly increasing if al<al+1<⋯<ar.

Input
The first line of the input contains one integer n (2≤n≤2⋅105) — the number of elements in a.

The second line of the input contains n integers a1,a2,…,an (1≤ai≤109), where ai is the i-th element of a.

Output
Print one integer — the maximum possible length of the strictly increasing contiguous subarray of the array a after removing at most one element.

Examples
Input
5
1 2 5 3 4
Output
4
Input
2
1 2
Output
2
Input
7
6 5 4 3 2 4 3
Output
2
Note
In the first example, you can delete a3=5. Then the resulting array will be equal to [1,2,3,4] and the length of its largest increasing subarray will be equal to 4.
题意:第一行给出一个数n,接下来给出n个数的序列。求在该序列中删去任意一个数后所得序列中的最长连续的递增子序列长度。
思路:用l[i]表示从左往右遍历,以编号为i的位置为起点的从左到右的最长连续的递增子序列的长度;用r[i]表示从右往左遍历,以编号为i的位置为起点的从右到左的最长连续的递增子序列的长度,该过程可用dp的方法来记录,然后用一个变量maxlen记录当前最大长度,最后从左到右遍历一遍,if(a[i]<a[i+2])(说明去掉i+1号位置后,以i号位置为终点的最长递增序列的最后一个数a[i]小于以i+2号位置为起点的最长递增序列的第一个数a[i+2],这样这两个递增序列就可以合并成一个更大的递增序列了),所以此时maxlen更新(即:maxlen=max(maxlen,l[i]+r[i+2]))

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<iomanip>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,a[maxn],l[maxn],r[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)//最初每个数都是一个长度为1的递增序列,所以初始化为1
        l[i]=1;
    for(int i=1;i<=n;i++)
        r[i]=1;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    int maxlen=1;
    for(int i=n-1;i>=1;i--)
    {
        if(a[i]<a[i+1]){
            r[i]=r[i+1]+1;//(如:1 2 3 5 2 4,r[i]依次为4 3 2 1 2 1)
        }
        maxlen=max(maxlen,r[i]);
    }
    for(int i=2;i<=n;i++)
    {
        if(a[i]>a[i-1]){
            l[i]=l[i-1]+1;//(如:1 2 3 5 2 4,l[i]依次为1 2 3 4 1 2)
        }
        maxlen=max(maxlen,l[i]);
    }
    for(int i=1;i<=n-2;i++)
    {
        if(a[i]<a[i+2]){
            maxlen=max(maxlen,l[i]+r[i+2]);
        }
    }
    cout<<maxlen<<endl;
    return 0;
}

C题

Three friends are going to meet each other. Initially, the first friend stays at the position x=a, the second friend stays at the position x=b and the third friend stays at the position x=c on the coordinate axis Ox.

In one minute each friend independently from other friends can change the position x by 1 to the left or by 1 to the right (i.e. set x:=x−1 or x:=x+1) or even don’t change it.

Let’s introduce the total pairwise distance — the sum of distances between each pair of friends. Let a′, b′ and c′ be the final positions of the first, the second and the third friend, correspondingly. Then the total pairwise distance is |a′−b′|+|a′−c′|+|b′−c′|, where |x| is the absolute value of x.

Friends are interested in the minimum total pairwise distance they can reach if they will move optimally. Each friend will move no more than once. So, more formally, they want to know the minimum total pairwise distance they can reach after one minute.

You have to answer q independent test cases.

Input
The first line of the input contains one integer q (1≤q≤1000) — the number of test cases.

The next q lines describe test cases. The i-th test case is given as three integers a,b and c (1≤a,b,c≤109) — initial positions of the first, second and third friend correspondingly. The positions of friends can be equal.

Output
For each test case print the answer on it — the minimum total pairwise distance (the minimum sum of distances between each pair of friends) if friends change their positions optimally. Each friend will move no more than once. So, more formally, you have to find the minimum total pairwise distance they can reach after one minute.

Example
Input
8
3 3 4
10 20 30
5 5 5
2 4 3
1 1000000000 1000000000
1 1000000000 999999999
3 2 5
3 2 6
Output
0
36
0
0
1999999994
1999999994
2
4
题意:就是 a b c 每个数都能+ - 1 或者不变,求间距和最小值。
思路:其实就是最大值最小值之间的关系

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<iomanip>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
    int t; cin >> t;
    while (t--)
    {
        int a, b, c; cin >> a >> b >> c;
        if (a == b && b == c)
        {
            cout << 0 << endl; continue;
        }
        int d = min(a, b);
        d = min(d, c);
        int e = max(a, b);
        e = max(e, c);

        d++; e--;
        if (d>=e)
            cout << 0 << endl;
        else cout << 2 * (e - d) << endl;
    }
    
}

D题

You are given an array a consisting of n integers. In one move, you can jump from the position i to the position i−ai (if 1≤i−ai) or to the position i+ai (if i+ai≤n).

For each position i from 1 to n you want to know the minimum the number of moves required to reach any position j such that aj has the opposite parity from ai (i.e. if ai is odd then aj has to be even and vice versa).

Input
The first line of the input contains one integer n (1≤n≤2⋅105) — the number of elements in a.

The second line of the input contains n integers a1,a2,…,an (1≤ai≤n), where ai is the i-th element of a.

Output
Print n integers d1,d2,…,dn, where di is the minimum the number of moves required to reach any position j such that aj has the opposite parity from ai (i.e. if ai is odd then aj has to be even and vice versa) or -1 if it is impossible to reach such a position.

Example
Input
10
4 5 7 6 7 5 4 4 6 4
Output
1 1 1 2 -1 1 1 3 1 1
题意:给一个数组arr,然后对于数组中1到n的位置pos,都可以跳向pos+arr[pos] 和pos-arr[pos],现在问题是:每一个位置跳向和它奇偶性相反的位置,最少需要几步。无法跳到则输出-1。
思路:这个题是看别人的。自己也是没掌握住,还是没写出来,看着别人的博客,感觉勉强能看懂。。。

#include<iostream>
#include <algorithm>
#include<string.h>
#include<cmath>
#include<queue>
#include<map>
#define inf 0x3f3f3f3f
#define ll long long
const int maxn = 200005;
using namespace std;
struct node
{
	int val, x, y;
}a[maxn];
vector<int> v[maxn];
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		a[i].x = a[i].y = inf;
		cin >> a[i].val;
		if (i + a[i].val <= n)
			v[i + a[i].val].push_back(i);
		if (i - a[i].val >= 1)
			v[i - a[i].val].push_back(i);
	}
	queue<int>q;
	for (int i = 1; i <= n; i++)
	{
		q.push(i);
	}
	while (!q.empty())
	{
		int head = q.front();
		q.pop();
		for (auto i : v[head])//v[head]中放的是下一次移动能到达head位置的点的编号,即上一个点的编号
		{
			if (a[head].val & 1)//如果head点值为奇数
			{
				if (a[i].x > 1 || a[i].y > a[head].y + 1)//head点为奇数值,那么它上一个点到奇数值点的最短距离只有1一种可能。i的x值更新为1,而y记录的是head点到下一个y点的距离
				{
					a[i].x = 1;
					if (a[i].y > a[head].y + 1)//位置i的点用对应的y继承位置head点到值为偶数的点的最短距离
						a[i].y = a[head].y + 1;
					q.push(i);
				}
			}
			else
			{
				if (a[i].y > 1 || a[i].x > a[head].x + 1)
				{
					a[i].y = 1;
					if (a[i].x > a[head].x + 1)
						a[i].x = a[head].x + 1;
					q.push(i);
				}
			}
		}
	}
	for (int i = 1; i <= n; i++)
	{
		if (a[i].val & 1)
		{
			cout << (a[i].y == inf ? -1 : a[i].y) << " ";
		}
		else
			cout << (a[i].x == inf ? -1 : a[i].x) << " ";
	}
}

E题

Recently, Norge found a string s=s1s2…sn consisting of n lowercase Latin letters. As an exercise to improve his typing speed, he decided to type all substrings of the string s. Yes, all n(n+1)2 of them!

A substring of s is a non-empty string x=s[a…b]=sasa+1…sb (1≤a≤b≤n). For example, “auto” and “ton” are substrings of “automaton”.

Shortly after the start of the exercise, Norge realized that his keyboard was broken, namely, he could use only k Latin letters c1,c2,…,ck out of 26.

After that, Norge became interested in how many substrings of the string s he could still type using his broken keyboard. Help him to find this number.

Input
The first line contains two space-separated integers n and k (1≤n≤2⋅105, 1≤k≤26) — the length of the string s and the number of Latin letters still available on the keyboard.

The second line contains the string s consisting of exactly n lowercase Latin letters.

The third line contains k space-separated distinct lowercase Latin letters c1,c2,…,ck — the letters still available on the keyboard.

Output
Print a single number — the number of substrings of s that can be typed using only available letters c1,c2,…,ck.

Examples
Input
7 2
abacaba
a b
Output
12
Input
10 3
sadfaasdda
f a d
Output
21
Input
7 1
aaaaaaa
b
Output
0
Note
In the first example Norge can print substrings s[1…2], s[2…3], s[1…3], s[1…1], s[2…2], s[3…3], s[5…6], s[6…7], s[5…7], s[5…5], s[6…6], s[7…7].
题意:给出一个字符串,然后给出k个字符,只保留字符串里k的字符的部分,然后求有多少个子串。
思路:求出这个k在字符串中的长度 之后带入公式

#include<iostream>
#include <algorithm>
#include<string.h>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
int n,k;
string s,s1;
int a[105];
ll sum=0,num=0;

int main(){
	cin>>n>>k;
	cin>>s;
	while(k--){
		cin>>s1;
		a[s1[0]-'a']=1;
	}	
	for(int i=0;i<=n;i++){
		if(a[s[i]-'a']==1){
			num++;
		}else{
			sum = sum + num*(num+1)/2;
			num=0;
		}
	}
	cout<<sum;
}

F题

Recently you have bought a snow walking robot and brought it home. Suppose your home is a cell (0,0) on an infinite grid.

You also have the sequence of instructions of this robot. It is written as the string s consisting of characters ‘L’, ‘R’, ‘U’ and ‘D’. If the robot is in the cell (x,y) right now, he can move to one of the adjacent cells (depending on the current instruction).

If the current instruction is ‘L’, then the robot can move to the left to (x−1,y);
if the current instruction is ‘R’, then the robot can move to the right to (x+1,y);
if the current instruction is ‘U’, then the robot can move to the top to (x,y+1);
if the current instruction is ‘D’, then the robot can move to the bottom to (x,y−1).
You’ve noticed the warning on the last page of the manual: if the robot visits some cell (except (0,0)) twice then it breaks.

So the sequence of instructions is valid if the robot starts in the cell (0,0), performs the given instructions, visits no cell other than (0,0) two or more times and ends the path in the cell (0,0). Also cell (0,0) should be visited at most two times: at the beginning and at the end (if the path is empty then it is visited only once). For example, the following sequences of instructions are considered valid: “UD”, “RL”, “UUURULLDDDDLDDRRUU”, and the following are considered invalid: “U” (the endpoint is not (0,0)) and “UUDD” (the cell (0,1) is visited twice).

The initial sequence of instructions, however, might be not valid. You don’t want your robot to break so you decided to reprogram it in the following way: you will remove some (possibly, all or none) instructions from the initial sequence of instructions, then rearrange the remaining instructions as you wish and turn on your robot to move.

Your task is to remove as few instructions from the initial sequence as possible and rearrange the remaining ones so that the sequence is valid. Report the valid sequence of the maximum length you can obtain.

Note that you can choose any order of remaining instructions (you don’t need to minimize the number of swaps or any other similar metric).

You have to answer q independent test cases.

Input
The first line of the input contains one integer q (1≤q≤2⋅104) — the number of test cases.

The next q lines contain test cases. The i-th test case is given as the string s consisting of at least 1 and no more than 105 characters ‘L’, ‘R’, ‘U’ and ‘D’ — the initial sequence of instructions.

It is guaranteed that the sum of |s| (where |s| is the length of s) does not exceed 105 over all test cases (∑|s|≤105).

Output
For each test case print the answer on it. In the first line print the maximum number of remaining instructions. In the second line print the valid sequence of remaining instructions t the robot has to perform. The moves are performed from left to right in the order of the printed sequence. If there are several answers, you can print any. If the answer is 0, you are allowed to print an empty line (but you can don’t print it).

Example
Input
6
LRU
DURLDRUDRULRDURDDL
LRUDDLRUDRUL
LLLLRRRR
URDUR
LLL
Output
2
LR
14
RUURDDDDLLLUUR
12
ULDDDRRRUULL
2
LR
2
UD
0
题意:尽可能少的删除无效或多余指令,并重新排列指令使机器人从原点出发,最后回到原点,中间不能经过同一个点两次(原点也仅能出发和结束经过)。
思路:想要回原点,那L和R数量需要相等,U和D数量需要相等;
如果竖直方向或水平方向不可以移动,那只能移一次水平或者竖直方向;
否则移个正方形即可;删除指令使L个数=R个数,U个数=D个数,就可以重新排列为正方形

#include<iostream>
#include <algorithm>
#include<string.h>
#include<cmath>
#include<queue>
#include<map>
int main(){
int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s);
        int len=strlen(s);
        int cnt[4];
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<len;i++)
        {
            if(s[i]=='U')
                cnt[0]++;
            if(s[i]=='D')
                cnt[1]++;
            if(s[i]=='L')
                cnt[2]++;
            if(s[i]=='R')
                cnt[3]++;
        }
        int mini1=0,mini2=0;
        //找到一组指令中较少个数的指令,以其个数为标准
        mini1=min(cnt[0],cnt[1]);
        mini2=min(cnt[2],cnt[3]);
        //若一组指中令有一个为0,则那一组指令都为0,且另一组两个只能走一步
        if(mini1==0&&mini2!=0)
            mini2=1;
        if(mini2==0&&mini1!=0)
            mini1=1;
        int sum=2*(mini1+mini2);
        printf("%d\n",sum);
        //按照自己设定的规则走,不重复且回到原点
        for(int i=0;i<mini1;i++)
            printf("U");
        for(int i=0;i<mini2;i++)
            printf("L");
        for(int i=0;i<mini1;i++)
            printf("D");
        for(int i=0;i<mini2;i++)
            printf("R");
        printf("\n");
    }
    return 0;

}



感想:因为自己 以前全在犹豫偷懒,今天下午才进群,晚上才了解到有一些contest,自己就火急火燎的写了下第一次的题目,自己这里面水题都能出来,有点难度的和难题,自己没写出来,都是参考其他博主的思路代码,我日后会继续跟紧步伐的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值