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);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章