Educational Codeforces Round 92 (Rated for Div. 2)题解总结

文章目录

  • A. LCM Problem
  • B. Array Walk
  • C. Good String
  • D. Segment Intersections

A. LCM Problem

Let LCM(x,y) be the minimum positive integer that is divisible by both x and y. For example, LCM(13,37)=481, LCM(9,6)=18.

You are given two integers l and r. Find two integers x and y such that l≤x

Input
The first line contains one integer t (1≤t≤10000) — the number of test cases.

Each test case is represented by one line containing two integers l and r (1≤l

Output
For each test case, print two integers:

if it is impossible to find integers x and y meeting the constraints in the statement, print two integers equal to −1;
otherwise, print the values of x and y (if there are multiple valid answers, you may print any of them).
Example
inputCopy
4
1 1337
13 69
2 4
88 89
outputCopy
6 7
14 21
2 4
-1 -1

题意:
给出l和r,能否找到x,y满足 l≤x

思路:
LCM至少为两倍,所以直接l,l*2

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int inf = 0x3f3f3f3f;
const int N = 2e5 + 7;
int a[105];
int main()
{
    int t;
    cin >> t;
    while (t--) 
    {
        int l, r; 
        scanf("%d%d", &l, &r);
        if (l * 2 > r) {
            printf("-1 -1\n");
        }
        else {
            printf("%d %d\n", l, l * 2);
        }
    }
    return 0;
}

B. Array Walk

You are given an array a1,a2,…,an, consisting of n positive integers.

Initially you are standing at index 1 and have a score equal to a1. You can perform two kinds of moves:

move right — go from your current index x to x+1 and add ax+1 to your score. This move can only be performed if x move left — go from your current index x to x−1 and add ax−1 to your score. This move can only be performed if x>1. Also, you can’t perform two or more moves to the left in a row.
You want to perform exactly k moves. Also, there should be no more than z moves to the left among them.

What is the maximum score you can achieve?

Input
The first line contains a single integer t (1≤t≤104) — the number of testcases.

The first line of each testcase contains three integers n,k and z (2≤n≤105, 1≤k≤n−1, 0≤z≤min(5,k)) — the number of elements in the array, the total number of moves you should perform and the maximum number of moves to the left you can perform.

The second line of each testcase contains n integers a1,a2,…,an (1≤ai≤104) — the given array.

The sum of n over all testcases does not exceed 3⋅105.

Output
Print t integers — for each testcase output the maximum score you can achieve if you make exactly k moves in total, no more than z of them are to the left and there are no two or more moves to the left in a row.

Example
inputCopy
4
5 4 0
1 5 4 3 2
5 4 1
1 5 4 3 2
5 4 4
10 20 30 40 50
10 7 3
4 6 8 2 9 9 7 4 10 9
outputCopy
15
19
150
56
Note
In the first testcase you are not allowed to move left at all. So you make four moves to the right and obtain the score a1+a2+a3+a4+a5.

In the second example you can move one time to the left. So we can follow these moves: right, right, left, right. The score will be a1+a2+a3+a2+a3.

In the third example you can move four times to the left but it’s not optimal anyway, you can just move four times to the right and obtain the score a1+a2+a3+a4+a5.

题意:
有n个数,从第一个位置开始走,可以选择向左或者向右走,然后获得下一步到达的那个数的值,向左向右走之后的位置不能越界,并且不能连续向左走两次以上,也就是一次向左走之前一定有一次向右走的操作.现在要求恰好经过k次移动并且向左走的次数不超过z,计算经过的数字之和的最大值.

思路:
使用dp,dp[i][j]这个数组的i表示移动的次数,j表示向左移的次数,在第i次移动时有两个选择向右移动,得到dp[i+1][j],此时的dp[i+1][j] = max(dp[i+1][j], dp[i][j]+buf[i-2*j+1]);这里面的i-2*j表示的是此时的位置,2*j表示向右移动一次和向左移动一次,buf[i-2*j+1]表示向右移动后下一个位置的值,这里面有一个约束条件i-2*j >= 0也就是回退的次数乘以2不能比此时可以移动的次数i大.如果此时回退的次数小于z-并且此时已经移动的次数i不大于k-2,那么可以向右移动一次再向左移动,然后移动次数加2,左移回退次数加1,得到dp[i+2][j+1],对应的语句是dp[i+2][j+1] = max(dp[i+2][j+1], dp[i][j]+buf[i-2*j+1]+buf[i-2*j]);

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int inf = 0x3f3f3f3f;
const int N = 1e5 + 7;
int buf[N];
int dp[N][10];

void solve(int n, int k, int z){
    memset(dp, 0, sizeof(dp));
    dp[0][0] = buf[0];
    for(int i = 0; i < k; ++i){
        for(int j = 0; j <= z; ++j){
            if( i - 2 * j < 0)
                break;
            dp[i+1][j] = max(dp[i+1][j], dp[i][j]+buf[i-2*j+1]);
            if( j < z && i + 2 <= k){
                dp[i+2][j+1] = max(dp[i+2][j+1], dp[i][j]+buf[i-2*j+1]+buf[i-2*j]);
            }
        }
    }
    int ans = 0;
    for(int i = 0; i <= z; i++){
        ans = max(ans, dp[k][i]);
    }
    cout<<ans<<endl;
}

int main(){
    int t;
    cin>>t;
    while(t--){
        int n,k,z;
        cin>>n>>k>>z;
        z = min(5,z);
        for(int i = 0; i < n; i++){
            cin>>buf[i];
        }
        solve(n,k,z);
    }
    return 0;
}

C. Good String

Let’s call left cyclic shift of some string t1t2t3…tn−1tn as string t2t3…tn−1tnt1.

Analogically, let’s call right cyclic shift of string t as string tnt1t2t3…tn−1.

Let’s say string t is good if its left cyclic shift is equal to its right cyclic shift.

You are given string s which consists of digits 0–9.

What is the minimum number of characters you need to erase from s to make it good?

Input
The first line contains single integer t (1≤t≤1000) — the number of test cases.

Next t lines contains test cases — one per line. The first and only line of each test case contains string s (2≤|s|≤2⋅105). Each character si is digit 0–9.

It’s guaranteed that the total length of strings doesn’t exceed 2⋅105.

Output
For each test case, print the minimum number of characters you need to erase from s to make it good.

Example
inputCopy
3
95831
100120013
252525252525
outputCopy
3
5
0
Note
In the first test case, you can erase any 3 characters, for example, the 1-st, the 3-rd, and the 4-th. You’ll get string 51 and it is good.

In the second test case, we can erase all characters except 0: the remaining string is 0000 and it’s good.

In the third test case, the given string s is already good.

题意:
给出字符串的长度和字符串。要求第一个字符和第二个字符不同,第三个和第四个不同…以此类推到第n-1和第n个字符不同,要求字符串的长度最后一定为偶数。求删除字符使其满足的最少次数和得到的字符串。

思路:
因为要求最后n一定为偶数,所以从右端点向左遍历一遍,如果有相同的就进行修改,跳一个单位;如果不同,不操作,跳两个单位。到最后,判断一下剩下的字符是否为奇数,若为奇数,则第一个字符删掉。

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int inf = 0x3f3f3f3f;
const int N = 2e5 + 7;
char c[N];
int main()
{
    int n,x,i,sum=0;
    scanf("%d",&n);
    scanf("%s",c+1);
    for(i=n;i>1;)
    {
        if(c[i]==c[i-1])
        c[i]='0',i=i-1,sum++;
        else
        i=i-2;
    }
    if((n-sum)%2==0)
    {
        printf("%d\n",sum);
        for(i=1;i<=n;i++)
        if(c[i]!='0')
        printf("%c",c[i]);
    }
    else
    {
        printf("%d\n",sum+1);
        for(i=2;i<=n;i++)
        if(c[i]!='0')
        printf("%c",c[i]);
    }
    return 0;
}

D. Segment Intersections

You are given two lists of segments [al1,ar1],[al2,ar2],…,[aln,arn] and [bl1,br1],[bl2,br2],…,[bln,brn].

Initially, all segments [ali,ari] are equal to [l1,r1] and all segments [bli,bri] are equal to [l2,r2].

In one step, you can choose one segment (either from the first or from the second list) and extend it by 1. In other words, suppose you’ve chosen segment [x,y] then you can transform it either into [x−1,y] or into [x,y+1].

Let’s define a total intersection I as the sum of lengths of intersections of the corresponding pairs of segments, i.e. ∑i=1nintersection_length([ali,ari],[bli,bri]). Empty intersection has length 0 and length of a segment [x,y] is equal to y−x.

What is the minimum number of steps you need to make I greater or equal to k?

Input
The first line contains the single integer t (1≤t≤1000) — the number of test cases.

The first line of each test case contains two integers n and k (1≤n≤2⋅105; 1≤k≤109) — the length of lists and the minimum required total intersection.

The second line of each test case contains two integers l1 and r1 (1≤l1≤r1≤109) — the segment all [ali,ari] are equal to initially.

The third line of each test case contains two integers l2 and r2 (1≤l2≤r2≤109) — the segment all [bli,bri] are equal to initially.

It’s guaranteed that the sum of n doesn’t exceed 2⋅105.

Output
Print t integers — one per test case. For each test case, print the minimum number of step you need to make I greater or equal to k.

Example
inputCopy
3
3 5
1 2
3 4
2 1000000000
1 1
999999999 999999999
10 3
5 10
7 8
outputCopy
7
2000000000
0
Note
In the first test case, we can achieve total intersection 5, for example, using next strategy:

make [al1,ar1] from [1,2] to [1,4] in 2 steps;
make [al2,ar2] from [1,2] to [1,3] in 1 step;
make [bl1,br1] from [3,4] to [1,4] in 2 steps;
make [bl2,br2] from [3,4] to [1,4] in 2 steps.
In result, I=intersection_length([al1,ar1],[bl1,br1])+intersection_length([al2,ar2],[bl2,br2])++intersection_length([al3,ar3],[bl3,br3])=3+2+0=5
In the second test case, we can make [al1,ar1]=[0,1000000000] in 1000000000 steps and [bl1,br1]=[0,1000000000] in 1000000000 steps.

In the third test case, the total intersection I is already equal to 10>3, so we don’t need to do any steps.

题意:
两个区间集和,各有n个区间,第一个区间集和初始都为[l1,r1][l1,r1],第二个区间集和初始都为[l2,r2][l2,r2]。一次操作可以将区间[x,y][x,y]变成[x−1,y][x−1,y]或者[x,y+1][x,y+1]。求区间交集为kk的最少操作次数

思路:
相交的长度×n已经满足条件 直接输出0。
否则先计算需要让两线段相交的操作数y,和一次操作数获得一个贡献的长度z,剩下则需要用两次操作获得一次贡献

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int inf = 0x3f3f3f3f;
const int N = 2e5 + 7;
int main()
{
	int t,n;
	ll k,l1,r1,l2,r2;
	scanf("%d",&t);
	while(t--)
	{
		cin>>n>>k>>l1>>r1>>l2>>r2;
		ll x=max(min(r1,r2)-max(l1,l2),0LL);
		if(k<=n*x){
			puts("0");continue;
		}
		k-=n*x; 
		ll y=max(max(l1,l2)-min(r1,r2),0LL);
		ll z=max(r1,r2)-min(l1,l2)-x;
		ll ans=1e18;
		for(int i=1;i<=n;i++){
			if(k<=i*z) ans=min(ans,i*y+k); 
			else ans=min(ans,i*(y+z)+(k-i*z)*2LL); 
		}
		printf("%lld\n",ans); 
	} 
	return 0;
}

你可能感兴趣的:(Codeforces)