Codeforces Round #481 (Div. 3) 题解
文章目录
A. Remove Duplicates
-  题意 
 给你一个有 n n n个整数的数组,现在需要删掉重复的元素,仅保留每个元素最右边的那个,且元素的相对顺序不应改变。
-  解题思路 
 利用 m a p map map记录每个值最后出现得位置,再桶排序输出即可。
-  AC代码 
/**
  *@filename:B
  *@author: pursuit
  *@created: 2021-08-11 18:59
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n;
int a[N];
int cnt = 0;
map<int,int> p;
void solve(){
    memset(a,0,sizeof(a));
    for(auto &x : p){
        a[x.second] = x.first;
    }
    cout << cnt << endl;
    for(int i = 1; i <= n; ++ i){
        if(a[i]){
            cout << a[i] << " ";
        }
    }
    cout << endl;
}
int main(){
    cin >> n;
    for(int i = 1; i <= n; ++ i){
        cin >> a[i];
        if(!p[a[i]]){
            cnt ++;
        }
        p[a[i]] = i;
    }	
    solve();
    return 0;
}
B. File Name
-  题意 
 给出一串字符串,判断里面有多少对xxx
-  解题思路 
 顺序遍历统计即可。
-  AC代码 
/*
*邮箱:unique_powerhouse@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h>	//POJ不支持
#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e5;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll>  pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//
int n;
string s;
int main(){
	//freopen("in.txt", "r", stdin);//提交的时候要注释掉
	IOS;
	while(cin>>n){
		cin>>s;
		ll ans=0;
		ll sum=0;
		rep(i,0,n-1){
			if(s[i]=='x'){
				sum++;
			}
			else{
				if(sum>=3){
					ans+=(sum-2);
				}
				sum=0;
			}
		}
		if(sum>=3){
			ans+=(sum-2);
		}
		cout<<ans<<endl;
	}
	return 0;
}
C. Letters
-  题意 
 有 n n n栋公寓,其中每个公寓有 a i a_i ai得房间,给出 m m m个信封所需送往的房间编号。判断所属门牌号。
-  解题思路 
 利用前缀和统计前 i i i个公寓的房间数,然后二分查找属于第几个公寓即可。
-  AC代码 
/**
  *@filename:C
  *@author: pursuit
  *@created: 2021-08-11 19:04
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,m;
ll a[N],b[N],sum[N];
void solve(){
    for(int i = 1; i <= m; ++ i){
        int idx = lower_bound(sum + 1,sum + 1 + n,b[i]) - sum;
        printf("%d %lld\n", idx,b[i] - sum[idx - 1]);
    }
}
int main(){	
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++ i){
        scanf("%lld", &a[i]);
        sum[i] = sum[i - 1] + a[i];
    }
    for(int i = 1; i <= m; ++ i){
        scanf("%lld", &b[i]);
    }
    solve();
    return 0;
}
D. Almost Arithmetic Progression
-  题意 
 给定一个整数序列,需要将这个序列变成等差数列。其中数列中的每个元素,都可以至多选择一种操作: − 1 , + 1 , -1,+1, −1,+1,保持不变。请输出最小操作次数。
-  解题思路 
 我们注意到,公差一定在相邻两数差值的最小值和最大值之内。而由于其操作限定性,所以 m a x − m i n ≤ 4 max-min\leq4 max−min≤4才有可能存在,其余的都不可能,处理好这个我们就可以枚举公差了,同时由于首项只有两种情况,我们也确定好首项然后验证合法性解决即可。注意特判 n ≤ 2 n\leq 2 n≤2的情况。
-  AC代码 
/**
  *@filename:D
  *@author: pursuit
  *@created: 2021-08-11 19:14
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const ll INF = 1e10;
int n;
ll b[N],minn = INF,maxx = -INF,c[N];
void solve(){
    bool flag = false;
    if(n <= 2){
        puts("0");
        return;
    }
    if(maxx - minn > 4){
        puts("-1");
    }
    else{
        ll ans = INF;
        for(int d = minn; d <= maxx; ++ d){
            for(int j = 0; j < 3; ++ j){
                for(int i = 1; i <= n; ++ i){
                    c[i] = b[i];
                }
                ll cnt = 0;
                bool flag = true;
                if(j == 1){
                    c[1] += 1;
                    cnt ++;
                }
                else if(j == 2){
                    c[1] -= 1;
                    cnt ++;
                }
                //cout << c[1] << " ";
                for(int i = 2; i <= n; ++ i){
                    if(abs(c[i] - c[i - 1] - d) > 1){
                        flag = false;
                        break;
                    }
                    else if(abs(c[i] - c[i - 1] - d) == 1){
                        cnt ++;
                        c[i] = c[i - 1] + d;
                    }
                    //cout << c[i] << " ";
                }
                //cout << endl;
                if(flag){
                    ans = min(ans,cnt);
                }
            }
        }
        if(ans == INF){
            puts("-1");
        }
        else{
            printf("%lld\n", ans);
        }
    }
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i){
        scanf("%lld", &b[i]);
        if(i >= 2){
            minn = min(minn,b[i] - b[i - 1]);
            maxx = max(maxx,b[i] - b[i - 1]);
        }
    }	
    solve();
    return 0;
}
E. Bus Video System
-  题意 
 公交车最多容纳w人,初始车上人数未知,经过n个站,每个站上车和下车人数给出,问车上一开始的人数有多少种可能,若方案不存在输出0。
-  解题思路 
 初始我们设置最小人数为 0 0 0,最多人数为 w w w,然后每次统计现有公交车人数,根据其合理性调整这两个数值。最后即是 m a x x − m i n n + 1 maxx-minn+1 maxx−minn+1。
-  AC代码 
/**
  *@filename:E
  *@author: pursuit
  *@created: 2021-08-11 19:29
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e3 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,w,a[N];
void solve(){
    int maxx = w,minn = 0;
    bool flag = false;
    int cur = 0;
    for(int i = 1; i <= n; ++ i){
        cur += a[i];
        if(cur + minn < 0){
            minn = 0 - cur;
        }
        else if(cur + maxx > w){
            maxx = w - cur;
        }
    }
    if(maxx < minn){
        puts("0");
    }
    else{
        printf("%d", maxx - minn + 1);
    }
}
int main(){	
    scanf("%d%d", &n, &w);
    for(int i = 1; i <= n; ++ i){
        scanf("%d", &a[i]);
    }
    solve();
    return 0;
}
F. Mentors
-  题意 
 在BerSoft n个程序员的工作中,程序员i的特点是技能ri。 当且仅当程序员a的技能严格大于程序员b的技能(ra> rb)且程序员a和b不吵架时,程序员a才可以是程序员b的指导者。系统会为您提供每个程序员的技能以及k对程序员的清单,它们在争吵中(对是无序的)。对于每个程序员i,找到程序员i可以担任其导师的程序员数量。
-  解题思路 
 存储好对应的技能和争吵关系,对于每个人二分查找得到多少个小于他的,同时再二分找出多少个小于他的且有争吵关系的,两者之差则是答案。
-  AC代码 
/**
  *@filename:F
  *@author: pursuit
  *@created: 2021-08-11 19:40
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,m,r[N],pos[N],ans[N];
vector<int> g[N];
bool cmp(int i,int j){
    return r[i] < r[j];
}
void solve(){
    sort(pos + 1,pos + 1 + n,cmp);
    for(int i = 1; i <= n; ++ i){
        sort(g[i].begin(),g[i].end(),cmp);
    }
    for(int i = 1; i <= n; ++ i){
        int u = pos[i],w = r[pos[i]];//寻找
        int L = 1,R = n;
        while(L < R){
            int mid = (L + R) >> 1;
            if(r[pos[mid]] < w){
                L = mid + 1;
            }
            else{
                R = mid;
            }
        }
        ans[u] = L - 1;
        if(g[u].size() != 0){
            //debug(u);
            int L = 0, R = g[u].size();
            while(L < R){
                int mid = (L + R) >> 1;
                if(mid == g[u].size()){
                    L = mid;
                    break;
                }
                int v = g[u][mid];
                //debug(v);
                if(r[v] < w){
                    L = mid + 1;
                }
                else{
                    R = mid;
                }
            }
            //cout << L << endl;
            ans[u] -= L;
        }
    }
    for(int i = 1; i <= n; ++ i){
        printf("%d ", ans[i]);
    }
    puts("");
}
int main(){	
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++ i){
        scanf("%d", &r[i]);
        pos[i] = i;
    }
    int u,v;
    for(int i = 1; i <= m; ++ i){
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    solve();
    return 0;
}
G. Petya’s Exams
-  题意 
 给你一些考试信息,有 n n n天可以用,问你可以合理安排的方案,若不存在,则输出 − 1 -1 −1。
-  解题思路 
 贪心即可,按考试时间从小到达排序,然后从开始准备日期开始准备。需要注意的一点就是不能占用其他考试日期。
-  AC代码 
/**
  *@filename:G
  *@author: pursuit
  *@created: 2021-08-11 20:53
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,m;
struct node{
    int id,s,d,c;//s为开始准备考试日期。d为考试日期,c为需要准备的考试天数。
    bool operator < (const node & A){
        return d < A.d;
    }
}item[N];
int ans[N];
bool vis[N];//考试不能占用。
void solve(){
    int cnt = 0;
    sort(item + 1,item + 1 + m);
    bool flag = true;
    for(int i = 1; i <= m; ++ i){
        int cnt = 0;
        for(int j = item[i].s; j < item[i].d && cnt < item[i].c; ++ j){
            if(!ans[j] && !vis[j]){
                ans[j] = item[i].id;
                cnt ++;
            }
        }
        if(cnt < item[i].c || ans[item[i].d]){
            flag = false;
            break;
        }
        else{
            ans[item[i].d] = m + 1;
        }
    }
    if(!flag){
        puts("-1");
    }
    else{
        for(int i = 1; i <= n; ++ i){
            printf("%d ", ans[i]);
        }
        puts("");
    }
}
int main(){	
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; ++ i){
        scanf("%d%d%d", &item[i].s, &item[i].d, &item[i].c);
        vis[item[i].d] = true;
        item[i].id = i;
    }
    solve();
    return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号