2019年10月3日CSP-Sシミュレーションテスト

例T1

質問の意味:

探している\(1 - N \)数の逆の順序で配置されている\(K \)配列の数

ソル:

私たちは、それは間違いなく除外ではありません知っている\(O(N!)\ ) アルゴリズム
考えてみましょう\(DP \) 今持っている\(N-1 \)の回答をし、多くの新しい生産する逆の順序で新しい番号を追加することを検討し
、設定された\(DP [I] [Jを ] \) を表す\(1 -iを\)配列\(J \)にかかわらず、多くの逆数が増加する場所に挿入添加新規の数の、反転対の数を
用いて\ [DP [I] [J ] = \和\限界^ {分(I - 1、J)} _ k個の
DP [I - 1] [J - K] \] 変化は形状こと、奇妙に見える\ [DP [I] [J ] = \和\限界^ J_ {MAX(0、J - I + 1} DP [I
- 1] [K] \] 複雑\(O(N-2 * K ^)\)、\ (O(実行しない)\)
I」のような接頭辞と最適化を検討長いハイ「と」に\(グレード\の作成)「と同じに
起因する\(K \)上部と結合\(J \)の変化を変化、サイクル時の蓄積を考える\(DP [I - 1 ] [J] \)変数、および、割り当てられた\(DP [I] [J
] \) なお\(K \)の下に結合しました\(J - I + 1 \ GEQ 0 \) の変化が発生し、多くを支払う減算することを忘れないでください

#include<bits/stdc++.h>
#define N (1000 + 10)
using namespace std;
int T;
int n, k, sum, f[N][N];
const int mod = 10000;
int main() {
    scanf("%d", &T);
    f[1][0] = 1;
    while (T--) {
        scanf("%d%d", &n, &k);
        if (f[n][k]) {printf("%d\n", f[n][k]); continue;}
        for (register int i = 2; i <= n; ++i) {
            sum = 0;
            for (register int j = 0; j <= k; ++j) {
                sum += f[i - 1][j] % mod;
                f[i][j] = sum % mod;
                if (j - i + 1 >= 0) sum -= f[i - 1][j - i + 1] % mod;
            }
        }
        printf("%d\n", f[n][k]);
    }
    return 0;
}

美しいT2

質問の意味:

数の値を定義\(V_I \)のメジアン間隔最大長として使用する\(Q \)は呼び掛け間隔クエリ\([L、R] \ ) 内の最大\(V_I \)を、最初のキー値、第二の標識されたキーの数によって、元のサイズと比較した場合
\(N \の当量2000、Q \の当量100000 \)

ソル:

参照してください\(N \)非常に小さく、それを操作する方法を考えることはできません

考えてみましょう\(O(N)\)は、すべての番号を列挙した後、右に拡張し、左、それぞれ、変数の記録\(S \)を、それがあろうよりも大きな遭遇\を( - S \) または\( S ++ \) そして各\(S \)レコードの値最も遠い位置であり、最終的に最大長を取得するために一緒に作品を撮る\(V_I \)を
何かやって、その後どれだけ\(RMQ \)をします

#include<bits/stdc++.h>
#define N (100000 + 10)
using namespace std;
inline int read() {
    int cnt = 0, f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
    return cnt * f;
}
int n, Q, l, r;
int S1[N], S2[N];
int a[N], b[N];
int t[N];
int A[N];
struct node {
    int l, r;
    int gmax;
    #define l(p) tree[p].l
    #define r(p) tree[p].r
    #define gmax(p) tree[p].gmax
}tree[N << 2];


void pushup(int p) {
    gmax(p) = max(gmax(p << 1), gmax(p << 1 | 1));
}

void build(int p, int l, int r) {
    l(p) = l, r(p) = r;
    if (l == r) {gmax(p) = A[l]; return;}
    int mid = (l + r) >> 1;
    build (p << 1, l, mid);
    build (p << 1 | 1, mid + 1, r);
    pushup(p);
}

long long query(int p, int l, int r) {
    if (l <= l(p) && r >= r(p)) return gmax(p);
    int mid = (l(p) + r(p)) >> 1;
    long long ans = -1;
    if (l <= mid) ans = max(ans, query(p << 1, l, r));
    if (r > mid) ans = max(ans, query(p << 1 | 1, l, r));
    return ans;
}

int main() {
    n = read(); for (register int i = 1; i <= n; ++i) a[i] = read();
    for (register int i = 1; i <= n; ++i) {
        int tmp = 0;
        memset(S1, 255, sizeof(S1));
        memset(S2, 255, sizeof(S2));
        S1[n] = S2[n] = 0;
        for (register int j = i - 1; j >= 1; --j) {
            if (a[j] > a[i]) ++tmp; if (a[j] <= a[i]) --tmp;
            S1[tmp + n] = i - j;
        }
        tmp = 0;
        for (register int j = i + 1; j <= n; ++j) {
            if (a[j] >= a[i]) ++tmp; if (a[j] < a[i]) --tmp;
            S2[tmp + n] = j - i;
        }
        for (register int j = 1 - i; j <= i - 1; ++j) if (S1[n + j] >= 0 && S2[n - j] >= 0) A[i] = max(A[i], S1[n + j] + 1 + S2[n - j]);
    } Q = read();
//  for (register int i = 1; i <= n; ++i) cout<<A[i]<<" ";return 0;
    build (1, 1, n);
    while (Q--) {
        l = read(), r = read();
        printf("%lld\n", query(1, l, r));
    }
    return 0;
}

T3サブセット

質問の意味:

一組の保持\(A \) 削除クエリの挿入サポート(a_iを\&S = a_iを\ )\ 数、\(a_iを\ A \で)、動作\(2E5 \) デジタルサイズ\(2 ^ {16 } \)

ソル:

素晴らしいアイデア
記録二つに分割数をバイナリ検討する、\(S [A] [Bは ] \) 最初の8ビットを表している\(\) 8がされた後、(B \)\サブセットを番号
のための\(追加\)\(デル\)指定された\(B \)列挙\(\)の更新
のための\(CNT \)所与の動作\(\)列挙\(B \)更新
クエリの複雑さと複雑さが最適化された時間変更のバランス\((OとN * 2 ^ 8)\)

#include<bits/stdc++.h>
#define N ((1 << 8) + 5)
using namespace std;
int Q, x;
char ope[5];
int s[N][N];
inline int read() {
    int cnt = 0, f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
    return cnt * f;
}
void add(int x) {
    int a = x >> 8, b = x - (a << 8);
    for (register int i = 0; i < (1 << 8); ++i) if ((i & a) == a) s[i][b]++;
}
void del(int x) {
    int a = x >> 8, b = x - (a << 8);
    for (register int i = 0; i < (1 << 8); ++i) if ((i & a) == a) s[i][b]--;
}
int query(int x) {
    int ans = 0, a = x >> 8, b = x - (a << 8);
    for (register int i = 0; i < (1 << 8); ++i) if ((i & b) == i) ans += s[a][i];
    return ans;
}
int main() {
    Q = read();
    while (Q--) {
        scanf("%s", ope + 1); x = read();
        if (ope[1] == 'a') add(x);
        if (ope[1] == 'd') del(x);
        if (ope[1] == 'c') printf("%d\n", query(x));
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/kma093/p/11621761.html
おすすめ