2019年9月24日シミュレーションゲーム

T1の週

トピックは水の上に隠されています
十分の$ O(2 ^ {15})$ DFS激しいです。

直接スローコード

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n;
const int MAXN = 20;
int a[MAXN], b[MAXN], c[MAXN], d[MAXN];
int ans = 0;
void dfs(int day, int oi, int whk) {
    if (day > n) {
        ans = max(ans, oi * whk);
        return;
    }
    dfs(day + 1, max(oi - b[day], 0ll), whk + a[day]);
    dfs(day + 1, oi + c[day], max(whk - d[day], 0ll));
}
signed main() {
    scanf("%lld", &n);
    for (register int i = 1; i <= n; ++i) scanf("%lld%lld%lld%lld", &a[i], &b[i], &c[i], &d[i]);
    dfs(0, 0, 0);
    printf("%lld\n", ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T2任意の

描画ボード上のそのような特性を満たすの黒と白の矩形領域:同じ色のブロックは上下四方に接続することができる場合、2つの黒の正方形か、任意の通信が、いずれか一方のみの単純なパスとの間の通信(同じのグリッドによるユニークなパス)。
この矩形領域\(N \) OK \(M \)最初のために上から下への列、\(1、2、3 ... N-1、N \) 行、最初のために左から右へ\(1、2、3 ... M-1、M \) カラム。
郭神はそれぞれの子供にこの長方形内の矩形を要求します。(即ち、としない連通長方形のサブ矩形の内部から副画素を超えて)サブ矩形内のピクセルのみを考慮した場合、サブ長方形の通信ブロックの数に黒い四角を尋ねます。
任意の2つのだけ黒画素間の単純なパスまで保証します。
##あなたがたが行う
節度に注意を払う
注意節度
注意節度の
タイトルは、中国聯通は、ツリーの一部であると言います。だから、全体像が森で、その後、どのように多くの星の木の範囲内で照会の対象に変換します。やる木の性質は何ですか?木が知られている\(\ N-)ポイント、\(。1-N- \)エッジを。我々はポイントやエッジの数を知っている場合は、木の数は、ツリーがポイントの辺の数であるカット。
木の点は、辺の数ができ\(O(NM)\)の前処理、再利用、二次元プレフィクスおよび実行することができるであろう\(O(1)\)クエリを。全体的に複雑\(O(NM + Q)\)

コード

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e3 + 5;
char mp[MAXN][MAXN];
bool v[MAXN][MAXN];
int sum1[MAXN][MAXN], sum2[MAXN][MAXN], sum3[MAXN][MAXN];
int step[][2] = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
int n, m, q;

inline void bfs() {
    queue<pair<int, int>> q;
    for (register int i = 1; i <= n; ++i)
        for (register int j = 1; j <= m; ++j) {
            if (mp[i][j] == '1' && !v[i][j]) {
                q.push(make_pair(i, j));
                while (q.size()) {
                    int x = q.front().first, y = q.front().second;
                    int xi, yi;
                    v[x][y] = true;
                    q.pop();
                    for (register int i = 0; i <= 0; ++i) {
                        xi = x;
                        yi = y + step[i][1];
                        if (mp[xi][yi] == '1' && !v[xi][yi] && xi >= 1 && xi <= n && yi >= 1 && yi <= m) {
                            ++sum3[x][y];
                            q.push(make_pair(xi, yi));
                        }
                    }
                }
            }
        }
    memset(v, 0, sizeof(v));
    for (register int i = 1; i <= n; ++i)
        for (register int j = 1; j <= m; ++j) {
            if (mp[i][j] == '1' && !v[i][j]) {
                q.push(make_pair(i, j));
                while (q.size()) {
                    int x = q.front().first, y = q.front().second;
                    int xi, yi;
                    v[x][y] = true;
                    q.pop();
                    for (register int i = 2; i <= 2; ++i) {
                        xi = x + step[i][0];
                        yi = y;
                        if (mp[xi][yi] == '1' && !v[xi][yi] && xi >= 1 && xi <= n && yi >= 1 && yi <= m) {
                            ++sum2[x][y];
                            q.push(make_pair(xi, yi));
                        }
                    }
                }
            }
        }
}
inline void test(int S[][MAXN]) {
    cerr << "-----##-----" << endl;
    for (register int i = 1; i <= n; ++i) {
        for (register int j = 1; j <= m; ++j) cerr << S[i][j] << " ";
        cerr << endl;
    }
}
inline void sum(int S[][MAXN]) {
    for (register int i = 1; i <= n; ++i)
        for (register int j = 1; j <= m; ++j) S[i][j] = S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1] + S[i][j];
}
inline int calc(int s[][MAXN], const int &a, const int &b, const int &c, const int &d) {
    register int t = s[c][d] + s[a - 1][b - 1] - s[c][b - 1] - s[a - 1][d];
    return t;
}
int main() {
#ifdef lky233
    freopen("duty.in", "r", stdin);
    freopen("duty.out", "w", stdout);
#endif
    scanf("%d %d %d", &n, &m, &q);
    for (register int i = 1; i <= n; ++i) scanf("%s", mp[i] + 1);
    bfs();
    for (register int i = 1; i <= n; ++i)
        for (register int j = 1; j <= m; ++j)
            sum1[i][j] = sum1[i - 1][j] + sum1[i][j - 1] - sum1[i - 1][j - 1] + (mp[i][j] - '0');
    sum(sum2);
    sum(sum3);
    for (register int i = 1, a, b, c, d; i <= q; ++i) {
        scanf("%d %d %d %d", &a, &b, &c, &d);
        printf("%d\n", calc(sum1, a, b, c, d) - calc(sum2, a, b, c - 1, d) - calc(sum3, a, b, c, d - 1));
    }
}

T3フライ

スペースの制約\(32MBの\)
liu_rundaは、知識のレベルを上げることを決めたので、彼はその高校の入学試験で投げるためにこの質問を入れて、神郭郭神は容易に、神のliu_runda質問を与えliu_rundaとしないだろう尋ねるに行ってきましたやります。
郭神\(N- \)バーは第一象限のセグメント内に配置され、各セグメントが与えられ\(X \)軸と\(Y \)ので、明らかにあなたが一意に各セグメントを識別することができ、交差点を軸。
\(N- \)の線分と\(Y \)縦軸の交点である\(1,2,3,4 ... N-\) 我々は覚えて\(Y \)軸交点座標\(Iは、\)や線(X \)\横軸の交点は、(X [I] + 1 \ \) このようにして生成:
\を( X [1] \)入力によって与えられます。\ [X [I] =( X [I-1] + A)、2 \当量iは当量を\ n \] すなわち:もし\([3]。Xが= 4 \) 次いで\(Y \)軸交点縦\(3 \)放物線および(X \)\横交差軸\(4 + 1 = 5 \)
我々は、与えられた保証(N [1]は、x \ 、MOD \) そのようなすべてのこと\(X [1] \)が互いに異なります。
第一象限内の全ての点(水平および垂直座標の点は、任意の実数とすることができる)ため、ドットがある場合\(X \)その鬼畜値介し線分れる(\ FRAC {Xの\回\ (X-1 )} {2} \)
最初の要求値鬼畜象限内のすべてのポイントと。

それを行う方法

まず、この式の特徴の一部。我々は2本の線が交差する場合、1を貢献しているだろうことがわかった、と3行が1点で交わる場合、いくつかがあった変換され、この質問のために、これに交差する三行に、それぞれ同等3を、貢献、およびています2線が交差する場合。
各ラインプラスy軸ので、ラインと交差する各ラインはxよりも大きいです。これまでのところ、この問題は、一次元の問題に変換されます。
推論した後、2つのアイデアがあります。


Xをソートするために時間を挿入するためによると、我々は逆の順番に残り、xおよびxは、彼の前に行数を貢献し、そうしているだろうときに問題が逆転しようとしているの問題となっていることが分かりました。
しかし、\(MOD \のLeq 10 ^ 8 \) 直接適合しないです。離散?\(N- \のLeq 10 ^ 7 \) 開いている場合、\(1E7の\)配列空間は、まだ爆発します。
分析\(X \)内の列の数\(X \)上方位置生成の寄与に対応する間隔の後であろう数の型が取られる前に、この時間間隔がインクリメントされ、寄与はこの間隔の間に発生しません、区間内の各数に対して、算術配列に対するこの寄与は、迅速に処理することができます。
各セグメントが等間隔であるので、我々は唯一の記録された各セグメント区間の開始位置が寄与は、対応する位置を生成\(X \)は逆数の上に形成され、各寄与は、区間長の逆を有することになります。以下のため\(X1の\)限界、最初のセグメントが完了していない、別々に計算される必要があります。\(\)の範囲内の\(1E5 \)は、この問題を容易に通過することができます。
おかげで\(@ jiqimao \)ギャングスターは、この優れたアルゴリズムを提供します。


これは私の悪いアルゴリズムです:
によると\(のx \)の位置をソートするために、我々はそれぞれのことを見つける(X \)\彼の後ろの生成の寄与がxの数です。同じこの期間を法の前に、\(X \)インクリメントされ、すべての時間\(X + \) (X \)\番号の前に数インターバル期間が減算されます。したがって、段落\(X \)貢献あなたは答えを得ることができ、算術級数、各サイクルの期間、です。

品質の悪いコード

算術シーケンス境界プロセスは、それが再発を行って、あまりにも面倒です。この暴力が実行されています

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 1e5 + 5;
int A[MAXN];
int a, mod, x1, n;
long long ans;
inline void add(int x) {
    for (; x <= a; x += x & (~x + 1)) A[x] += 1;
}
inline int ask(int x) {
    int ans = 0;
    for (; x; x -= x & (~x + 1)) ans += A[x];
    return ans;
}
inline int calc(int a1, int d, int n) { return a1 * n + (n * (n - 1)) * d; }
signed main() {
    cin >> n >> x1 >> a >> mod;

    for (register int i = 1, now = x1, cnt = 0, lun = 0; i <= n; ++i) {
        if (now >= a) {
            cnt -= lun;
            if (x1 > now)
                ++cnt;
            ans += cnt;
        } else
            cnt = i - 1 - ask(now + 1), ans += cnt, add(now + 1);
        now += a;
        if (now >= mod)
            now -= mod, ++lun;
    }
    cout << ans << endl;
}

おすすめ

転載: www.cnblogs.com/Shiina-Rikka/p/11584458.html