CodeForces - 978C,D,E,F

写在前面,这是我们的一场训练赛,也是我爆零的一场,很高兴,这场比赛让我认识到我的很多缺陷,也将成为我前进路上的动力!
传送门:https://codeforces.com/problemset/problem/978/C
Codeforces Round #481 (Div. 3)CDEF
Letters CodeForces - 978C
There are n dormitories in Berland State University, they are numbered with integers from 1 to n. Each dormitory consists of rooms, there are ai rooms in i-th dormitory. The rooms in i-th dormitory are numbered from 1 to ai.

A postman delivers letters. Sometimes there is no specific dormitory and room number in it on an envelope. Instead of it only a room number among all rooms of all n dormitories is written on an envelope. In this case, assume that all the rooms are numbered from 1 to a1+a2+⋯+an and the rooms of the first dormitory go first, the rooms of the second dormitory go after them and so on.

For example, in case n=2, a1=3 and a2=5 an envelope can have any integer from 1 to 8 written on it. If the number 7 is written on an envelope, it means that the letter should be delivered to the room number 4 of the second dormitory.

For each of m letters by the room number among all n dormitories, determine the particular dormitory and the room number in a dormitory where this letter should be delivered.

Input
The first line contains two integers n and m (1≤n,m≤2⋅105) — the number of dormitories and the number of letters.

The second line contains a sequence a1,a2,…,an (1≤ai≤1010), where ai equals to the number of rooms in the i-th dormitory. The third line contains a sequence b1,b2,…,bm (1≤bj≤a1+a2+⋯+an), where bj equals to the room number (among all rooms of all dormitories) for the j-th letter. All bj are given in increasing order.

Output
Print m lines. For each letter print two integers f and k — the dormitory number f (1≤f≤n) and the room number k in this dormitory (1≤k≤af) to deliver the letter.

Input
3 6
10 15 12
1 9 12 23 26 37
Output
1 1
1 9
2 2
2 13
3 1
3 12
Input
2 3
5 10000000000
5 6 9999999999
Output
1 5
2 1
2 9999999994
Note
In the first example letters should be delivered in the following order:

the first letter in room 1 of the first dormitory
the second letter in room 9 of the first dormitory
the third letter in room 2 of the second dormitory
the fourth letter in room 13 of the second dormitory
the fifth letter in room 1 of the third dormitory
the sixth letter in room 12 of the third dormitory
题意很清晰,给我们n个宿舍,每个宿舍有一定的房间数,
给我们m封信,问信会分到哪个房间,题中有关键暗示。
in case n=2, a1=3 and a2=5 an envelope can have any integer from 1 to 8 written on it. 
If the number 7 is written on an envelope, 
it means that the letter should be delivered to the room number 4 of the second dormitory.
有两个宿舍,第一个宿舍有3个房间,第二个宿舍有5个房间。信封7将会送到第二个宿舍的第4个房间。

怎么做呢?就是看信封是否比第一个宿舍的房间号大,如果小,就直接输出。
否则就比较信封和前两个宿舍房间号的大小关系,依次类推
先放一个我当时错误的代码,当时想着放着信封的数组去遍历房间的数组。
但是有一个问题,每次算的时候,信封的变量j一直会从1开始
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b)for(int i=a;i<=b;i++)
#define rep1(i,a,b)for(int i=a;i<b;i++)
#define rep2(i,a,b)for(int i=b;i>=a;i--)
using namespace std;
const int maxn =1e5+10;
int n,m;
int a[maxn];
int b[maxn];
int main(){
    scanf("%d%d",&n,&m);
   rep(i,1,n)
    scanf("%d",&a[i]);
    rep(i,1,m)
    scanf("%d",&b[i]);
    rep(i,1,m){
        rep(j,1,n){
        if(a[i]>=b[j])
            printf("%d %d\n",i,b[j]);
        }
    }
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b)for(int i=a;i<=b;i++)
#define rep1(i,a,b)for(int i=a;i<b;i++)
#define rep2(i,a,b)for(int i=b;i>=a;i--)
using namespace std;
const int maxn=3e5+10;//runtime error 一般需要考虑数组是否开小了
int n,m;
ll a[maxn];
ll b[maxn];
ll sum[maxn]={0};
int main(){
    scanf("%d%d",&n,&m);
    rep(i,1,n)
    scanf("%lld",&a[i]);
    rep(i,1,m)
    scanf("%lld",&b[i]);
    int j=1;//j放在外面,就只遍历一次
    rep(i,1,n){
        sum[i]=sum[i-1]+a[i];//用前缀和来维护房间的数组
        for(;j<=m;j++){
            if(b[j]<=sum[i])
                printf("%d %lld\n",i,b[j]-sum[i-1]);
            else break;
        }
    }
    return 0;
}

```c
二分做法
 #include <bits/stdc++.h>
 #define ll long long
 using namespace std;
 const int N = 2e5+10;
 ll a[N], b[N];
 int main() {
     ll n, m;
      cin >> n >> m >> a[0];
      b[0] = a[0];
     for(int i = 1; i < n; i ++) {
         cin >> a[i];
         b[i] = b[i-1] + a[i];
     }
     while(m--) {
         ll x;
         cin >> x;
         int id = lower_bound(b,b+n,x) -b;
         printf("%d %lld\n",id+1,a[id]-(b[id]-x));
     }
     return 0;
 }

 Almost Arithmetic Progression   
 CodeForces - 978D 
 Polycarp likes arithmetic progressions. A sequence [a1,a2,…,an] is called an arithmetic progression if for each i (1≤i<n) the value ai+1−ai is the same. For example, the sequences [42], [5,5,5], [2,11,20,29] and [3,2,1,0] are arithmetic progressions, but [1,0,1], [1,3,9] and [2,3,1] are not.

It follows from the definition that any sequence of length one or two is an arithmetic progression.

Polycarp found some sequence of positive integers [b1,b2,…,bn]. He agrees to change each element by at most one. In the other words, for each element there are exactly three options: an element can be decreased by 1, an element can be increased by 1, an element can be left unchanged.

Determine a minimum possible number of elements in b which can be changed (by exactly one), so that the sequence b becomes an arithmetic progression, or report that it is impossible.

It is possible that the resulting sequence contains element equals 0.

Input
The first line contains a single integer n (1≤n≤100000) — the number of elements in b.

The second line contains a sequence b1,b2,…,bn (1≤bi≤109).

Output
If it is impossible to make an arithmetic progression with described operations, print -1. In the other case, print non-negative integer — the minimum number of elements to change to make the given sequence becomes an arithmetic progression. The only allowed operation is to add/to subtract one from an element (can't use operation twice to the same position).

```c
Input
4
24 21 14 10
Output
3
Input
2
500 500
Output
0
Input
3
14 5 1
Output
-1
Input
5
1 3 6 9 12
Output
1
Note
In the first example Polycarp should increase the first number on 1, decrease the second number on 1, increase the third number on 1, and the fourth number should left unchanged. So, after Polycarp changed three elements by one, his sequence became equals to [25,20,15,10], which is an arithmetic progression.

In the second example Polycarp should not change anything, because his sequence is an arithmetic progression.

In the third example it is impossible to make an arithmetic progression.

In the fourth example Polycarp should change only the first element, he should decrease it on one. After that his sequence will looks like [0,3,6,9,12], which is an arithmetic progression.
题意说的是,元素有三种变化,第一种是元素不变,第二种是+1,第三种是-1.
问给你一段序列,能否使他们成为等差数列。
举个例子:4
24 21 14 10
a[1]-a[0]=-3,a[2]-a[1]=-7,a[3]-a[2]=-4;
怎么做才能使他们成为等差数列呢?根据口算我们可以知道当序列为25 20 15 10
的时候可以是等差数列。
我们让a[0]+1,此时a[1]-a[0]=-4,我们让a[1]-1,此时a[1]-a[0]=-5,
同样地a[2]-a[1]也发生变化,变成-6,这样我们知道前一项的变化影响后一项的变化。
这道题很好的思路是,先枚举前两个数的变化,然后在推广到整个数列。
先固定一段,在变。
//后来发现是先枚举前两组可能然后算出公差。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b)for(int i=a;i<=b;i++)
#define rep1(i,a,b)for(int i=a;i<b;i++)
#define rep2(i,a,b)for(int i=b;i>=a;i--)
using namespace std;
const int maxn=3e5+10;
int n;
int arr[maxn];
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&arr[i]);
    int a=arr[0],b=arr[1];
    int ans=inf;
    if(n<=2){
        printf("0\n");
        return 0;
    }
    for(int i=0;i<9;i++){
        int cnt=0;
        if(i==0){
            arr[0]=a;
            arr[1]=b;
            cnt=0;
        }
        if(i==1){
            arr[0]=a;
            arr[1]=b+1;
            cnt=1;
        }
        if(i==2){
            arr[0]=a;
            arr[1]=b-1;
            cnt=1;
        }
        if(i==3){
            arr[0]=a-1;
            arr[1]=b;
            cnt=1;
        }
        if(i==4){
            arr[0]=a-1;
            arr[1]=b+1;
            cnt=2;
        }
        if(i==5){
            arr[0]=a-1;
            arr[1]=b-1;
            cnt=2;
        }
        if(i==6){
            arr[0]=a+1;
            arr[1]=b;
            cnt=1;
        }
        if(i==7){
            arr[0]=a+1;
            arr[1]=b+1;
            cnt=2;
        }
        if(i==8){
            arr[0]=a+1;
            arr[1]=b-1;
            cnt=2;
        }
        int j=2;
        int m=arr[1]-arr[0];
        int last=arr[1];
        for(;j<n;j++){
            if(arr[j]-last==m){
                last=arr[j];
                continue;
            }
            else if(arr[j]-last==m-1){
                last=arr[j]+1;
                cnt++;
                continue;
            }
            else if(arr[j]-last==m+1){
                last=arr[j]-1;
                cnt++;
                continue;
            }
            else
                break;
        }
        //printf("%d\n",j);
        if(j==n)
            ans=min(ans,cnt);
    }
    if(ans==inf)//表示cnt没有加过,不符合(后一项减前一项与前一项减前二项和的差值间隔)
        printf("-1\n");
    else
        printf("%d\n",ans);
    return 0;
}

Bus Video System CodeForces - 978E
The busses in Berland are equipped with a video surveillance system. The system records information about changes in the number of passengers in a bus after stops.

If x is the number of passengers in a bus just before the current bus stop and y is the number of passengers in the bus just after current bus stop, the system records the number y−x. So the system records show how number of passengers changed.

The test run was made for single bus and n bus stops. Thus, the system recorded the sequence of integers a1,a2,…,an (exactly one number for each bus stop), where ai is the record for the bus stop i. The bus stops are numbered from 1 to n in chronological order.

Determine the number of possible ways how many people could be in the bus before the first bus stop, if the bus has a capacity equals to w (that is, at any time in the bus there should be from 0 to w passengers inclusive).

Input
The first line contains two integers n and w (1≤n≤1000,1≤w≤109) — the number of bus stops and the capacity of the bus.

The second line contains a sequence a1,a2,…,an (−106≤ai≤106), where ai equals to the number, which has been recorded by the video system after the i-th bus stop.

Output
Print the number of possible ways how many people could be in the bus before the first bus stop, if the bus has a capacity equals to w. If the situation is contradictory (i.e. for any initial number of passengers there will be a contradiction), print 0.

Input
3 5
2 1 -3
Output
3
Input
2 4
-1 1
Output
4
Input
4 10
2 4 1 2
Output
2
Note
In the first example initially in the bus could be 0, 1 or 2 passengers.

In the second example initially in the bus could be 1, 2, 3 or 4 passengers.

In the third example initially in the bus could be 0 or 1 passenger.
题意问你,第一站公交车上车之前的人数可能,如果没有打印0
题中给个暗示:
如果公交车的容量等于w,则打印在第一个公共汽车站之前可以有多少人乘坐公共汽车的方式。
如果情况相互矛盾(即对于任何初始乘客数量都会有矛盾),请打印0。
我们可以先算出,公交车站上车之前可能的最大人数,在算出最小人数。就ok了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b)for(int i=a;i<=b;i++)
#define rep1(i,a,b)for(int i=a;i<b;i++)
#define rep2(i,a,b)for(int i=b;i>=a;i--)
using namespace std;
const int maxn=3e5+10;
int n,m;
int main(){
    while(~scanf("%d %d",&n,&m)){
        int sum=0;
        int x;
        int maxx=0,minn=0;
        rep(i,1,n)
        {
            scanf("%d",&x);
            sum+=x;
            maxx=max(maxx,sum);
            minn=min(minn,sum);
        }
        maxx=m-maxx;//第一站上车前车上最多有多少人,容量-最大值
        if(minn<0)
            minn=-minn;//最少车上开始有多少人,为啥minn=-minn呢?
            //举个例子:如果车的容量为5,最小值为-4,那么首站上车前是不是至少得
            //有4个人呢?如果有3个人的话,人数就会变成负的。
        else
            minn=0;
        int ans=maxx-minn+1;//加1,是因为从0计起
        if(ans<0)
            printf("0\n");//矛盾,输出0
        else
            printf("%d\n",ans);
    }
    return 0;
}

Mentors CodeForces - 978F
In BerSoft n programmers work, the programmer i is characterized by a skill ri.

A programmer a can be a mentor of a programmer b if and only if the skill of the programmer a is strictly greater than the skill of the programmer b (ra>rb) and programmers a and b are not in a quarrel.

You are given the skills of each programmers and a list of k pairs of the programmers, which are in a quarrel (pairs are unordered). For each programmer i, find the number of programmers, for which the programmer i can be a mentor.

Input
The first line contains two integers n and k (2≤n≤2⋅105, 0≤k≤min(2⋅105,n⋅(n−1)2)) — total number of programmers and number of pairs of programmers which are in a quarrel.

The second line contains a sequence of integers r1,r2,…,rn (1≤ri≤109), where ri equals to the skill of the i-th programmer.

Each of the following k lines contains two distinct integers x, y (1≤x,y≤n, x≠y) — pair of programmers in a quarrel. The pairs are unordered, it means that if x is in a quarrel with y then y is in a quarrel with x. Guaranteed, that for each pair (x,y) there are no other pairs (x,y) and (y,x) in the input.

Output
Print n integers, the i-th number should be equal to the number of programmers, for which the i-th programmer can be a mentor. Programmers are numbered in the same order that their skills are given in the input.

Input
4 2
10 4 10 15
1 2
4 3
Output
0 0 1 2 
Input
10 4
5 4 1 5 4 3 7 1 2 5
4 6
2 1
10 8
3 5
Output
5 4 0 5 3 3 9 0 2 5 
Note
In the first example, the first programmer can not be mentor of any other (because only the second programmer has a skill, lower than first programmer skill, but they are in a quarrel). The second programmer can not be mentor of any other programmer, because his skill is minimal among others. The third programmer can be a mentor of the second programmer. The fourth programmer can be a mentor of the first and of the second programmers. He can not be a mentor of the third programmer, because they are in a quarrel.
题目大意:给你n个程序员的数量,m对处于争吵中的程序员的编号,如果满足
一个程序员的能力值比另一个高,并且没有与另一个程序员争吵,则可成为导师,问
每个程序员最多能成为几个程序员的导师。
一个程序员只能与一个程序员处在争吵之中

求小于ai的数有多少,并且减去和i有争吵的。
先排序,二分查找小于ai的数有多少个,然后看与 i 有争吵的数是否小于ai,小于的话减一。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const int N = 2e5+10;
int a[N], b[N], n, k;
vector<int> vs[N];
int main() {
    cin >> n >> k;
    for(int i = 0; i < n; i ++) {
        cin >> a[i];
        b[i] = a[i];//把a数组赋给另一个数组,然后将另一个数组排序。a数组不能动
    }
    sort(b,b+n);
    for(int i = 1, u, v; i <= k; i ++) {
        cin >> u >> v;
        vs[u-1].push_back(v-1);
        vs[v-1].push_back(u-1);
        //有两层意思:一个是表示u和v是处于争吵的关系
        //另一个是记录与他争吵人的下标
        //可以把vector看成一个不定长的容器,并不一定是二维数组
        //开n个vector个,对于每一个vector(定义为vis[n]),每一个vis[i]表示存放这第i名同学会争吵的人。
        //vis[1]={2,3,5}或者vis[1][0]=2,vis[1][1]=3,vis[1][2]=5(两个是一样的,两种表示方式而已),就代表1会和2 3 5争吵。
        //一位山农学长的指导,感谢
//vis[2]={1,3}或者vis[2][0]=1,vis[2][1]=3,表示2会和1,3争吵
    }
    for(int i = 0; i < n; i ++) {
        int id =lower_bound(b,b+n,a[i])-b;
        for(int j = 0; j<vs[i].size(); j ++) {
            if(a[vs[i][j]] < a[i]) id--;//表示与i处于争吵的,且能力值比i低
        }
        printf("%d ",id);
    }
    printf("\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值