問題のCF R#579 Div.3ソリューション

タイトル

以下のような列挙については、位置1を探しています。

Bタイトル

固定の面積は、Bよりも長い長い長さを二乗した場合、それは、ソート後の配列の幅Bよりも短いパルス幅必要があり、それが地域のことは明らかである\(* A_N A_1 \) 二回から中間に並べ替えのように列挙。

Cのタイトル

探しているシーケンス\(A \)すべての数字の数除数。
直接\(O(nlogn)\)すべての数の最小公倍数を得た\(G \) 次いで\(O(\ SQRT {G })\) 列挙\(G \)の約数であり、数答えはあります。

Dタイトル

簡単にバージョン

暴力の列挙は、部分文字列を削除し、暴力の裁判官は、その答えを更新します。
時間複雑\(O(N ^ 3)\)

ハードバージョン

暴力は明らかに退屈な繰り返し計算をたくさん持っています。
CF公式ソリューション:

ましょう\(rg_i \)であるような右端の位置\(X \)\(S \)サブストリングその;(\ [| | T I] T)\のサブシーケンスである[; | | S X] \(S \) 私たちは、値が必要です\(rg_i \)すべてについて\(私は\)から\(1 \)をするために\(| T | \) 私達はちょうどのすべての文字の上に右から左に反復することを計算することができます\(複数可\)と文字列へのポインタを維持する\(のt \)簡単なバージョンのように。
その後のすべての位置を反復しましょう(私は\)\から\(1 \)する(\ | | S)\とポインタの維持(\ POS)\を私たちのプレフィックスの最大長告げる簡単なバージョンのように\(トンの\を)我々は唯一の部分文字列使用して取得することができます(S [1; I)\を\) !(独占的に)。我々はの部分文字列削除するとします\(複数可\)から始まる\(私は\) そして、もし\(pos≤| T | \)その後ましょう\(RPOS \) BE \(rg_pos-1 \) それ以外ましょう\(RPOS \) BE \(|よ| \) \(RPOS \)我々は削除することができ、サブストリングの最右端の文字を教えてくれる。だから我々は、値との答えを更新することができます\(RPOS-I + 1 \)と次の位置(と増加することを忘れないでくださいに行く\(POSの\を)必要な場合)。

前処理効果\(RG \)アレイ、\(rg_i \)から\を(私は\)出発\(T \)からサフィックス\(rg_i \)出発\(S \)サフィックスストリング。もちろん、右のほとんど。我々は一致列挙削除する場合は、\を(複数可\)現在の左端\(のt \)に一致する位置\(POSは、\)されます\(O(1)\)右の境界線を削除するように計算され、その答えを更新することができます。

時間計算量は()O(N + M \ \)

コード:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<set>
#include<cmath>
#include<cstdlib>
#include<ctime>

using namespace std;

#define FOR(a, b, c) for(int a = b; a <= c; a++)

const int mx = 2*1e5 + 5;
const int inf = 1<<30;

void fre() {
    freopen(".txt", "r", stdin);
    freopen(".txt", "w", stdout);
}

char s[mx], t[mx];
int n, m;
int rg[mx];

int main(){
    //fre();
    scanf("%s %s", s, t);
    int n = strlen(s), m = strlen(t);
    for(int i = m-1; i >= 0; i--) {
        int pos = n-1;
        if(i + 1 < m) pos = rg[i+1]-1;
        while(s[pos] != t[i]) pos--;
        rg[i] = pos;
    }
    
    int ans = 0;
    int pos = 0;
    FOR(i, 0, n-1) {
        int rpos = n-1;
        if(pos < m) rpos = rg[pos]-1;
        ans = max(ans, rpos - i + 1);
        if(pos < m && s[i] == t[pos]) pos++;
    }
    cout << ans << endl;
    return 0;
}

Eタイトル

貪欲なタイトル。
最初のターンで考慮、降順、維持\(W \)現在の最大のために、もし現在の\(w_i + 1 \) \(<\)\(W \) 彼を取る、との答えを更新します、それ以外の場合は順番に考慮さ\(w_i \) \(w_i-1 \)スキップしません。
コード:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<set>
#include<cmath>
#include<cstdlib>
#include<ctime>

using namespace std;

#define FOR(a, b, c) for(int a = b; a <= c; a++)

const int mx = 1.5e5 + 5;
const int inf = 1<<30;

void fre() {
    freopen(".txt", "r", stdin);
    freopen(".txt", "w", stdout);
}

int n, a[mx];

int main(){
    //fre();
    cin >> n;
    FOR(i, 1, n) scanf("%d", &a[i]);
    sort(a+1, a+n+1); reverse(a+1, a+n+1);
    int Max = inf;
    int ans = 0;
    FOR(i, 1, n) {
        int res = -1;
        for(int x = 1; x >= -1; x--) {
            if(a[i] + x > 0 && a[i] + x < Max) {
                res = a[i] + x;
                break;
            }
        }
        if(res == -1) continue;
        ans++;
        Max = res;
    }
    cout << ans << endl;
    return 0;
}

おすすめ

転載: www.cnblogs.com/Maktub-blog/p/11371821.html