問題への2019頭の牛オフより学校第三ソリューション

問題への2019頭の牛オフより学校第三ソリューション

トピックリンク

B.Crazyバイナリ列

接頭辞、解答部分文字列維持するために、シーケンスと\(* 2分(0,1) \) 番号を。


コード

#include<bits/stdc++.h>
typedef long long ll;
const int MAXN = 1e5 + 5, MAXM = 1e5 + 5, INF = 0x3f3f3f3f, MOD = 998244353;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
using namespace std;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pb push_back
#define random(a,b) ((a)+rand()%((b)-(a)+1))
typedef double db;
int n, cnt[2], mp[MAXN << 1], delta = 100000;
char t[MAXN];
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> n;
    cin >> (t + 1);
    int sum = 0, ans = 0;
    for (int i = 1; i <= n; i++) {
        cnt[t[i] - '0']++;
        if (t[i] == '1')sum++;
        else sum--;
        if (sum == 0)ans = max(ans, i);
        if (mp[sum + delta]) {
            ans = max(ans, i - mp[sum + delta]);
        }
        else mp[sum + delta] = i;
    }
    cout << ans << ' ' << min(cnt[0], cnt[1]) * 2 << '\n';
    return 0;
}

D.Big整数

容易に入手可能な\(A(N)= \ FRAC {10 ^ N - 1} {9} \) 問題が要件であるので、\は((N)= \ FRAC {10 ^ N-1} {9} = 0( モッズP)\)
考えてみた(p!= 3 \)\がされて\((10 ^ N - 1)* INV(9)= 0(MOD P)\) ので\(INV(9)!= 0 \)ので、式サブまで低減することができる\(^ N-10 = 1(MOD P)\)

検討\(pは!= 2、P != 5 \)の場合であり、そこである(GCD(10、P)= 1 \)\、そう\(10 ^ {\ varphi( P)} = 1(MODPを)\) 以来\(^ 0 = 10 1(MOD P)\)は、ループセクションことを知ることができる\(\ varphi(P)1-P = \) 我々は今、最小ループ部の必要\(dは\を)、そして確実に満たす- | \(1)\(P D)我々がライン上で直接暴力を列挙しよう、。

次のステップは、すべて見つけることです(。1 \のLeq Iは、n-のLeq ,. 1つの\のLeq J \のLeq m個の\を\)\、満たす| \(^ I jは\ dの ) 番号を。\(D \)は:のように分解される\(P_1 K_1} ^ {^ {P_2 P_T K_2 ...}} ^ {K_T \)次に、上記条件を満足しなければならない、(G = P_1 ^ {\ \ lceil \ FRAC {K_1} {J} \ rceil} P_2 ^ {\ lceilの\のFRAC {K_2} {J} \ rceil} ... P_T ^ {\ lceilの\のFRAC {K_T} {J} \ rceil} |私は\) この時点で\(Iは\)の数である(\ \ {N-FRAC {G}} \) 列挙した後\(j個\)ライン上の、我々は唯一のためにここに列挙(30 \)を\、そしてより大きな値が同じです。場合は\(P = 2 || P = 5 \) 、明白な答えがさ(0 \)\します

今検討した(p = 3 \)\そうである場合、番号について、ケース(3 \)\の倍数、その上方位置のそれぞれの数を、それがされている(3 \)\倍数。この問題のために、それが必要とされる(I ^ J = 0(\ )3 MOD \) すべて\(I、J \)番号を。ライン上での直接のカウント。

詳細なバーコードを参照してください、この問題は置くことができない\(9 \)を列挙するために直接移動するのに約\(\ varphi(9P)\ ) 除数を。しかし、int型よりも弾性率のために、長い長いバーストかもしれません。

コードは以下の通りであります:


コード

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5, INF = 1e9;
int T;
int n, m, p;
ll qp(ll a, ll b, int P) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % P;
        a = a * a % P;
        b >>= 1;
    }
    return ans;
}
int pri[N], cnt[N], k;
void work(int x, int *a, int *b) {
    k = 0;
    for(int i = 2; 1ll * i * i <= x; i++) {
        if(x % i == 0) {
            a[++k] = i; int c = 0;
            while(x % i == 0) c++, x /= i;
            b[k] = c;
        }
    }
    if(x > 1) {
        a[++k] = x; b[k] = 1;
    }
}
int solve(int j) {
    int x = 1;
    for(int i = 1; i <= k; i++) {
        int t = (cnt[i] + j - 1) / j;
        while(t--) x *= pri[i];
    }
    return n / x;
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> p >> n >> m;
        if(p == 2 || p == 5) {
            cout << 0 << '\n';
            continue ;
        }
        if(p == 3) {
            cout << 1ll * m * (n / 3) << '\n';
            continue;
        }
        int phi = p - 1, d = INF;
        for(int i = 1; 1LL * i * i <= phi; i++) {
            if(phi % i == 0) {
                if(qp(10, i, p) == 1) d = min(d, i);
                if(qp(10, phi / i, p) == 1) d = min(d, phi / i);
            }
        }
        work(d, pri, cnt);
        ll ans = 0;
        for(int j = 1; j <= min(30, m); j++) ans += solve(j);
        if(m > 30) ans += 1ll * (m - 30) * solve(30);
        cout << ans << '\n';
    }
    return 0;
}

F.Planting木

書き込みを開始()はO(n ^ 3logn \を \) 2次元テーブルST、=は=過去にカードなしで
、その後、実際にライン上で単調なキューを向け、列挙長方形の上下の境界は、右の境界を列挙最小実現可能な左を維持ボーダー。以来左境界は、より複雑な非減少である\(O(N ^ 3)\) ライン上に記録するためのポインタで叶います。
コードは以下の通りであります:


コード

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 505, INF = 1e9;
    int T;
    int n, m;
    int a[N][N];
    int cmx[N], cmn[N];
    int q1[N], q2[N];
    int l1, r1, l2, r2;
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> n >> m;
            int ans = 0;
            for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) cin >> a[i][j];
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= n; j++) cmx[j] = 0, cmn[j] = INF;
                for(int j = i; j <= n; j++) {
                    for(int k = 1; k <= n; k++) cmx[k] = max(cmx[k], a[j][k]), cmn[k] = min(cmn[k], a[j][k]);
                    l1 = l2 = 1; r1 = r2 = 0;
                    int p = 1;
                    for(int k = 1; k <= n; k++) {
                        while(l1 <= r1 && cmx[q1[r1]] <= cmx[k]) r1--;
                        q1[++r1] = k;
                        while(l2 <= r2 && cmn[q2[r2]] >= cmn[k]) r2--;
                        q2[++r2] = k;
                        while(cmx[q1[l1]] - cmn[q2[l2]] > m) {
                            p++;
                            if(l1 <= r1 && q1[l1] < p) l1++;
                            if(l2 <= r2 && q2[l2] < p) l2++;
                            if(p > k) break;
                        }
                        ans = max(ans, (j - i + 1) * (k - p + 1));
                    }
                }
            }
            cout << ans << '\n';
        }
        return 0;
    }

G.Removingストーンズ

インターバルの期間であり、次のように勝利条件を見出すことができる(。sum_r-sum_ {} 1-L> = 2 * MX \)\
パーティションは、ライン上の他の二点間隔(枚方、2つの分割セクション、小さな列挙の範囲その間隔の最大値の位置のために、考慮することができるように、最大間隔部は、二つの部分に分けることができます複雑さの広い範囲のために代わりにO(N ^ 2)に還元することができる\(O(nlogn)\) )。
複雑\(O(nlognlogn)\) ほとんどの目の位置を求めることも必要テーブル、またはあなたよT.


コード

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 300005;
int T;
int n;
int a[N];
ll sum[N];
ll ans;
int f[N][19], pos[N][19];
int lg[N];
void init() {
    for(int i = 1; i <= n; i++) f[i][0] = a[i], pos[i][0] = i;
    for(int j = 1; j <= 18; j++) {
        for(int i = 1; i + (1 << j) - 1 <= n; i++) {
            if(f[i][j - 1] > f[i + (1 << (j - 1))][j - 1]) {
                pos[i][j] = pos[i][j - 1];
            } else pos[i][j] = pos[i + (1 << (j - 1))][j - 1];
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]) ;
        }
    }
}
int query(int l, int r) {
    int k = lg[r - l + 1];
    if(f[l][k] > f[r - (1 << k) + 1][k]) return pos[l][k];
    return pos[r - (1 << k) + 1][k];
}
void solve(int l, int r) {
    if(r - l <= 0) return;
    if(r - l == 1) {
        if(a[l] == a[r]) ans++;
        return;
    }
    int k = query(l, r);
    int mx = a[k];
    if(k - l < r - k) {
        for(int L = l; L <= k; L++) {
            int LL = k, RR = r + 1, mid;
            while(LL < RR) {
                mid = (LL + RR) >> 1;
                if(sum[mid] - sum[L - 1] - mx >= mx) RR = mid;
                else LL = mid + 1;
            }
            ans += (r - LL + 1);
        }
    } else {
        for(int R = k; R <= r; R++) {
            int LL = l ,RR = k + 1, mid;
            while(LL < RR) {
                mid = (LL + RR) >> 1;
                if(sum[R] - sum[mid - 1] - mx >= mx) LL = mid + 1;
                else RR = mid;
            }
            ans += (LL - l);
        }
    }
    solve(l, k - 1); solve(k + 1, r);
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    for(int i = 2; i < N; i++) lg[i] = lg[i >> 1] + 1;
    cin >> T;
    while(T--) {
        cin >> n; ans = 0;
        for(int i = 1; i <= n; i++) cin >> a[i], sum[i] = sum[i - 1] + a[i];
        init();
        solve(1, n);
        cout << ans << '\n';
    }
    return 0;
}

H.Magicライン

わずかに傾斜した直線を考慮した後、X、Yソートによる。


コード

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1005, INF = 1e8;
int T;
struct point{
    int x, y;
    bool operator < (const point &A)const {
        if(x == A.x) return y < A.y;
        return x < A.x;
    }
}a[N];
int n;
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i].x >> a[i].y;
        sort(a + 1, a + n + 1);
        if(a[n / 2].x == a[n / 2 + 1].x) {
            cout << a[n / 2].x - 1 << ' ' << a[n / 2].y + INF << ' ' << a[n / 2 + 1].x + 1 << ' ' << a[n / 2 + 1].y - INF << '\n';
        } else {
            cout << a[n / 2].x << ' ' << -INF << ' ' << a[n / 2 + 1].x << ' ' << INF << '\n';
        }
    }
    return 0;
}

I.Median

結論あります\(a_iを\)その中央値の1に影響を与える等しくなければなりませんが。
証明は、その後、あなたは最終的にそれを見つけるだろう、それをプッシュすることができます\(a_iをを\)または番号3に等しいより大きい、より小さいか等しい、明らかに実現可能なことと同等を取ります。
移行後\(DP \)は、現在そのため\(Iは\)(I-2、I-1 \)\ から転送させて\(DP [I] [J ] [k]を\) 表す\(Iは\)最初に関連付けられたビット\(J + 1 \)大き桁、\(1-I \)セクションに関連付けられているビット\(K + 1 \)サイズビット数、および最終的にから\(DP [I-1] [K] [L] \) の転送にわたって。
\(V [I] [J ] \) の効果であり、記憶されている\(Iは\)の数\(J + 1 \)サイズの桁。
転送は、ライン上の前駆体で記録されている場合。
メモこの状態で正当正面である場合、他方は充填されている決定正当性は、ビットの現在の数を満たすために等しい\(I-B_を1} {\) 添字内部コード\(I-1 \ )実際に\(I-2 \)
以下のようにコードは次のようになります。


コード

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int T;
int b[N], a[N];
int dp[N][3][3], v[N][3], pre[N][3][3];
int n;
int med(int x, int y, int z) {
    int tmp[3];
    tmp[0] = x, tmp[1] = y, tmp[2] = z;
    sort(tmp, tmp + 3);
    return tmp[1];
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        for(int i = 1; i <= n; i++)
            for(int j = 0; j < 3; j++)
                for(int k = 0; k < 3; k++)
                    dp[i][j][k] = pre[i][j][k] = 0;
        cin >> n;
        for(int i = 2; i < n; i++) cin >> b[i];
        b[0] = b[1] = b[2];
        b[n + 1] = b[n] = b[n - 1];
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j < 3; j++) {
                v[i][j] = b[i + j - 1];
            }
            sort(v[i], v[i] + 3);
        }
        for(int i = 1; i <= 2; i++)
            for(int j = 0; j < 3; j++)
                for(int k = 0; k < 3; k++)
                    dp[i][j][k] = 1;
        for(int i = 3; i <= n; i++) {
            for(int j = 0; j < 3; j++) {
                for(int k = 0; k < 3; k++) {
                    for(int l = 0; l < 3; l++) {
                        if(!dp[i - 1][k][l]) continue;
                        if(med(v[i - 2][l], v[i - 1][k], v[i][j]) != b[i - 1]) continue;
                        dp[i][j][k] = 1;
                        pre[i][j][k] = l;
                    }
                }
            }
        }
        int x = -1, y = -1;
        for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) {
            if(dp[n][i][j]) {
                x = i, y = j;
                break ;
            }
        }
        if(x == -1 || y == -1) {
            cout << -1 << '\n';
            continue ;
        }
        for(int i = n; i >= 1; i--) {
            a[i] = v[i][x];
            x = pre[i][x][y];
            swap(x, y);
        }
        for(int i = 1; i <= n; i++) cout << a[i] << ' ' ;
        cout << '\n';
    }
    return 0;
}

J.LRU管理

直接シミュレーション、もう少し詳しく。


コード

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 500005, M = 15;
int T;
char s[M];
int st, ed, sz;
int q, m;
int L[N], R[N], data[N];
int trie[N * 10], pos[N * 10], ch[N * 10][10], tot;
void trieInsert(int it, char *s){
    assert(strlen(s) <= 10);
    int p = 0;
    for (int i = 0; s[i]; i++){
        int &t = ch[p][s[i] - '0'];
        if (!t) t = ++tot; p = t;
    }
    pos[trie[it] = p] = it;
}

int trieFind(char *s){
    int p = 0;
    for (int i = 0; s[i]; i++){
        p = ch[p][s[i] - '0'];
        if(!p) return 0;
    }
    return pos[p];
}
void Erase(int x){
    int pre = L[x], succ = R[x];
    if (pre) R[pre] = succ;
    if (succ) L[succ] = pre;
    data[x] = L[x] = R[x] = 0;
    if (x == st) st = succ;
    if (x == ed) ed = pre;
    --sz;
}

void Insert(int x, int v){
    data[x] = v;
    if (!st) st = ed = x;
    else L[R[ed] = x] = ed, ed = x;
    ++sz;
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        st = ed = sz = 0;
        pos[tot = 0] = 0;
        cin >> q >> m;
        int num = 0;
        while(q--) {
            int op, v;
            cin >> op >> s + 1 >> v;
            int it = trieFind(s + 1);
            if(op == 1) {
                if(!it || (v == 1 && !R[it]) || (v == -1 && !L[it])) cout << "Invalid" << '\n';
                else {
                    if(v == -1) it = L[it];
                    if(v == 1) it = R[it];
                    cout << data[it] << '\n';
                }
            } else {
                if(it) {
                    v = data[it];
                    Erase(it);
                }
                if(sz == m) pos[trie[st]] = 0, Erase(st);
                Insert(++num, v);
                trieInsert(num, s + 1);
                cout << v << '\n';
            }
        }
        for(int i = 0; i <= tot; i++) {
            for(int j = 0; j < 10; j++) ch[i][j] = 0;
            pos[i] = trie[i] = 0;
        }
        while(st) Erase(st);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/heyuhhh/p/11260357.html