Codeforces 1082B(vector的应用) 题解 + 1088C(思维) 题解

Codeforces 1082B: http://codeforces.com/contest/1082/problem/B

题意:

给你一个串,只包含S和G这两个字符,让你最多交换一次 S和G的位置,使得连续的G的长度达到最长,打印这个最大长度。

思路:

记两个vector,分别存每个 S 前面有几个连续的 G,后面有几个连读的 G,然后用max维护一下,这两个值的和的最大值,有一点需要注意,那就是,如果,当前找到的这个S,前后的连续G加起来,就是总的G的个数,那么你这个S只能和这里面开头或者结尾的G交换才能达到最大,即当前维护到的这个max值就是答案,否则,就意味着,你当前枚举到的这个S,可以和一个其他的G进行交换,这里的 “其他的”,指的除去当前S左右两端的连续G以外的G,所以此时维护到的max还要加上S交换过来的G,即max + 1 才是最后结果。

我的AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 7;
const int Mod = 4e3 + 1;
const int Inf = 1 << 30;
const ll INF = 1ll << 60;
#define mst(x) memset(x, 0, sizeof(x))
map <int, int> mp;
set <int> sst;
typedef pair <int, int> PR;
priority_queue <PR> qua;
int n;
char s[maxx];
vector <int> vecFr;
vector <int> vecBk;
vector <int> vec;

void Init() {
    scanf("%d", &n);
    scanf("%s", s + 1);
}

int main() {
    Init();
    int fr = 0;
    int cnt = 0;
    for(int i = 1; i <= n; i++) {
        if(s[i] == 'S') {
            cnt++;
            vecFr.push_back(fr);
            fr = 0;
        }
        else fr++;
    }
    int bk = 0;
    for(int i = n; i >= 1; i--) {
        if(s[i] == 'S') {
            vec.push_back(bk);
            bk = 0;
        }
        else bk++;
    }
    int sz = vec.size();
    for(int i = sz - 1; i >= 0; i--) vecBk.push_back(vec[i]);
    /*for(int i = 0; i < sz; i++)
      cout << vecFr[i] << ' ' << vecBk[i] << endl;*/
    int ans = 0;
    for(int i = 0; i < sz; i++) {
        ans = max(ans, vecFr[i] + vecBk[i]);
    }
    for(int i = 0; i < sz; i++) {
        if(vecFr[i] + vecBk[i] == ans) {
            if(vecFr[i] + vecBk[i] < n - cnt) ans++;
            break;
        }
    }
    if(!cnt) cout << n << endl;
    else cout << ans << endl;
}

 

Codeforces 1088C: http://codeforces.com/problemset/problem/1088/C

题意:

给你一个长度为 n (n <= 2000) 的序列 a (a[i] <= 1e5),你只能进行如下两种操作:

1) 将前缀 k 全部加x

2) 将前缀 k 全部模x

最多进行 n + 1 次,使得这个序列严格递增。

打印操作步数和具体操作。

思路:

既然他都说了,最多进行n + 1步,那我就进行n + 1步,首先我要让这个序列严格递增,我就最后让这个序列的值,全变成他的角标,即1 2 3 4 ...。那么我就首先给这个序列的每个数都加上一个相对大的书Mod,那我怎么确定这个 Mod 值呢,首先我要想让 a[i] 都变成他的角标 i,那我就让 a[i] 每次进行操作2,模的是 (a[i] - i),但是如果我当前 a[i] 里有多于一个 (a[i] - i),那么我这个余数值就不准确了,因此,我需要满足以下两个条件

a[i] % (a[i] - i) = i

a[i]  / (a[i] - i) = 1

所以我只需要让 a[i] / (a[i] - i) < 2,即 a[i] > 2i,即可,那么我 i 的取值就是n的取值范围,最大是2e3,而我当前 a[i] 就是 a[i] + Mod,由于 0 <= a[i] <= 1e5,因此我的Mod值取一个4e3 + 1(取4e3不行,因为a[i] = 0时,a[i] + Mod 不一定能保证大于2 * i),就能满足上述情况了,所以,我直接进行 n + 1步,第一步,给前缀 n 全加上Mod,然后每次让前缀模 (a[i] - i) 就能满足严格递增了。

我的AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 7;
const int Mod = 4e3 + 1;
const int Inf = 1 << 30;
const ll INF = 1ll << 60;
#define mst(x) memset(x, 0, sizeof(x))
typedef pair <int, int> PR;
priority_queue <PR> qua;
vector <int> vec;
set <int> sst;
map <int, int> mp;
int n;
int a[maxx];

void Init() {
    mst(a);
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
        a[i] += Mod;
    }
}

int main() {
    Init();
    cout << n + 1 << endl;
    printf("1 %d %d\n", n, Mod);
    for(int i = 1; i <= n; i++) {
        int dd = a[i] - i;
        printf("2 %d %d\n", i, dd);
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值