• 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
    ", ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    

    T2任

    在画板上有一片黑白相间的矩形区域满足这样的性质:如果认为相同颜色的方块可以在上下左右四个方向连通,那么任意两个黑色方块要么不连通,要么连通但之间只有一条简单路径(不重复经过同一个格子的路径)。
    这个矩形区域有(N)(M)列, 从上到下依次为第(1, 2, 3... N-1, N)行, 从左到右依次为第(1, 2, 3... M-1, M)列。
    每次郭神会询问这片矩形区域内的一个子矩形。在只考虑这个子矩形内的像素时(即从子矩形内部不能和子矩形之外的像素相连通),问这个子矩形内的黑色方块组成了多少连通块。
    保证任意两个黑色像素之间最多只有一条简单路径。

    咋做

    注意审题
    注意审题
    注意审题
    题里说了联通的部分是一棵树。所以整张图是一个森林,那么题目的询问转化为了这个范围内有多少颗树。树有什么性质呢?众所周知树有(n)个点,(n-1)条边。当我们已知点数和边数,树的棵数就是点数减边数。
    树的点数、边数可以(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
    ", 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 leq i leq n$$即:如果(x[3] = 4),则与(y)轴交点纵坐标为(3)的抛物线和(x)轴交点的横坐标为(4+1=5)
    我们保证给出的(n,x[1],a,mod)使得所有的(x[1])互不相同。
    对于第一象限内的所有点(点的横纵坐标可以是任意实数),如果一个点被(x)条线段经过, 它的鬼畜值就是(frac {x imes (x-1)}{2})
    第求一象限内的所有点的鬼畜值之和。

    怎么做呢

    首先分析这个有些特点的算式。我们发现如果两条线相交,会产生1的贡献,而如果三条线交于一点,会产生3的贡献,与三条线分别相交等价,以此类推,这个题被转化为求出现了几次两条线相交的情况。
    由于线在y轴每次加一,每条线只会与x比它大的线相交。至此,这个问题转化为了一维的问题。
    之后的推理有两种思路。


    按照插入时间来对x排序,我们发现,当x与其余x逆序时,会产生他前面的线个数的贡献,这样这个问题就变成了求逆序对的问题。
    但是(mod leq 10^8),直接做是放不下的。离散化?(n leq 10^7),如果开一个(1e7)的数组空间依旧爆炸。
    分析(x)这个数列,在(x)被取模之前,这一段区间是递增的,这段区间内不会产生贡献,而它会与上一个区间对应位置之后的数产生贡献,对区间内的每个数来说,这个贡献成等差数列,可以快速进行处理。
    对应位置产生的贡献,由于每段区间是规律的,因此我们仅记录每段区间起始位置的(x)形成的逆序对个数,每个逆序对将会产生该区间长度的贡献。由于(x1)的限制,第一段并不完整, 需要单独计算。(a)的范围是(1e5),可以轻松通过此题。
    感谢 (@jiqimao)大佬提供了这个优秀的算法。


    这个是我的差劲算法:
    按照(x)的位置进行排序,我们发现每个(x)所产生的贡献是他后边x的个数。同样的在取模前这一段内,(x)递增,而每次(x+a)后,排在(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;
    }
    
  • 相关阅读:
    QT自定义信号和槽
    C++中深入理解dynamic_cast
    C++中rapidxml用法
    VS2015 创建C++动态库及使用
    C++ 已知两个时间(年月日)求日期差
    Electron 打开开发者工具 devtools
    NSIS安装或卸载时检查程序是否正在运行
    sqlite3 读写锁
    CEF 远程调试
    linux缩减分区空间,用以安装win系统
  • 原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11584458.html
Copyright © 2020-2023  润新知