zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 8 部分题解

    C. Bear and String Distance

    简单题,直接从距离范围最宽广的字母开始选,每次贪心选最大的。

    const int MAXN = 1e5 + 10;
     
    int n, k;
    char ss[MAXN];
     
    struct E { char s, t; int id; } es[MAXN];
     
    int dist(char x, char y) { return std::abs(x - y); }
     
    bool cmp1(E x, E y) { return x.s > y.s; }
    bool cmp2(E x, E y) { return x.id < y.id; }
     
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n >> k;
        cin >> (ss + 1);
        rep (i, 1, n) { es[i].s = ss[i]; es[i].id = i; }
        std::sort(es + 1, es + 1 + n, cmp1);
        int _validator = 0;
        rep (i, 1, n) {
            int d = std::min(k, std::max(dist('a', es[i].s), dist('z', es[i].s)));
            if (es[i].s + d > 'z') es[i].t = es[i].s - d;
            else es[i].t = es[i].s + d;
            k -= d;
            _validator += dist(es[i].s, es[i].t);
        }
        if (k) {
            cout << -1 << endl; return 0;
        }
        std::sort(es + 1, es + 1 + n, cmp2);
        rep (i, 1, n) cout << es[i].t;
        cout << endl;
        return 0;
    }
    

    D. Magic Numbers

    数位 DP 基础题,状态是考虑从高到第 (mathrm{pos}) 位,该前缀 (mod 13) 的值,是否触碰上限。

    因为保证上下界数字长度相同所以就不需要考虑前导零了,问题简化了很多。

    别忘了开 long long。

    const int MAXN = 2000 + 10;
    const int HA = 1e9 + 7;
     
    int m, d;
     
    char ss[MAXN];
     
    int divnum[MAXN], cnt;
     
    lli dp[MAXN][MAXN];
    lli dfs(int pos, int rmd, bool limit, int len) {
        if (pos == 0) return rmd == 0;
        if (!limit && dp[pos][rmd] != -1) return dp[pos][rmd];
        lli ans = 0;
        int top = limit ? divnum[pos] : 9;
        for (int i = 0; i <= top; ++i) {
            if (((len - pos + 1) % 2 == 0) ^ (i == d)) continue;
            ans += dfs(pos - 1, (rmd * 10 + i) % m, limit && (i == divnum[pos]), len);
            ans %= HA;
        }
        if (!limit) dp[pos][rmd] = ans;
        return ans;
    }
    void divide() {
        int len = (int) strlen(ss + 1);
        cnt = 0;
        for (int i = len; i >= 1; --i) divnum[++cnt] = ss[i] - '0';
    }
    lli Solve() {
        divide();
        memset(dp, -1, sizeof dp);
        return dfs(cnt, 0, true, cnt);
    }
     
    bool check() {
        int bmod = 0;
        for (int i = 1; i <= cnt; ++i) {
            if ((i % 2 == 0) ^ ((ss[i] - '0') == d)) return false;
            bmod = bmod * 10 + ss[i] - '0';
            bmod %= m;
        }
        return bmod == 0;
    }
     
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> m >> d;
        cin >> (ss + 1);
        lli ans1 = Solve() - check();
        (ans1 += HA) %= HA;
        // DEBUG(ans1);
        cin >> (ss + 1);
        lli ans2 = Solve();
        // DEBUG(ans2);
        cout << (ans2 - ans1 + HA) % HA << endl; 
        return 0;
    }
    
    

    E. Zbazi in Zeydabad

    挺有意思一题。

    定义 z 线:指一条连续的全部由字符 z 组成的线段,可能是斜的也可能是横的。

    首先我们可以预处理出所有点往左 tl[i][j]、往右 tr[i][j],往左下 tld[i][j] 的最长横 z 线长度,这对于我们判断 Z 字形有很大的用处。

    注意到 Z 字形的结构是正方形,所以确定了一个角和长度就可以确定整个图形的位置;而且对角线角(左下、右上)是和图形的对角线部分直接相关的,所以考虑枚举图形的右上角 ((i, j))

    可以发现,这个图形可能的最大长度即是往左和往左下 z 线长度的较小值 l = min(tl[i][j], tld[i][j]),于是接下来我们的任务就是判断这条长为 (l) 的斜 z 线上有多少满足,经过它的横 z 线向右伸展达到(或超过)这个右上角所在列 (j),的点,以这些点作为左下角即可确定一个 Z 字形。直接枚举是 (O(n^3)) 级别的,考虑能不能优化。

    5bfa7Q.png

    注意到以我们枚举的点为右上角的所有 Z 字形有两个性质:

    它们下面那一条横 z 线都至少向右伸展达到(或超过)了右上角所在列 (j)
    它们所有的左下角一定分布在这条长为 (l) 的斜 z 线上,也就是在对角线上的一个区间查询。

    因此我们可以考虑去寻找所有右端点在 (j) 上(或右边)的横 z 线,它们的左端点如果在这条对角线斜 z 线上,就说明这个左端点是满足要求的一个左下角。

    这个所有线是 (O(n^3)) 级别的,但是发现相同左端点的横 z 线只会产生一个贡献,而且右端点肯定尽量靠右最好,所以我们就只保留每一个点往右伸展最长长度的横 z 线,也就是对于点 ((x, y)),我们要存的线段是 ((x, y) ightarrow (x, y + mathrm{tr}_{x, y} - 1))(如果存在的话)。

    接下来的任务就是,对于这个右上角 ((i, j)),枚举所有右端点也在列 (j) 上(或超过)的线段,判断它的左端点是不是在这条对角线上,而且属于这个长为 (l) 的区间。

    类似树状数组求逆序对,这里我们也可以使用类似于边插入边查询的思想,考虑对每一条对角线维护一个树状数组,(b_{x + y, y}) 表示当前(x + y) 条对角线上是否存在以第 (y) 列的点为左端点的线段(0 或 1),通过以合适的顺序枚举线段并修改树状数组,我们可以实现在对角线上的区间查询。

    为了满足线段所有右端点都在当前枚举的列右边,我们修改枚举右上角 ((i, j)) 的顺序,先从右往左枚举列 (j),找到所有右端点在列 (j) 上的线段,将左端点插入对应对角线的树状数组;再从上到下枚举行 (i),确定右上角 ((i, j)),在对应对角线的树状数组上进行区间查询,累计答案即可。

    const int MAXN = 3000 + 10;
    
    int n, m;
    char mat[MAXN][MAXN];
    
    int tl[MAXN][MAXN], tr[MAXN][MAXN], tld[MAXN][MAXN];
    std::vector<std::pair<int, int> > segs[MAXN]; // segs[r][x] -> LeftNode(i, j)
    void pre() {
        rep (i, 1, n) {
            rep (j, 1, m) if (mat[i][j] == 'z') tl[i][j] = tl[i][j - 1] + 1;
            for (int j = m; j >= 1; --j) if (mat[i][j] == 'z') tr[i][j] = tr[i][j + 1] + 1;
        }
        for (int i = n; i >= 1; --i) {
            rep (j, 1, m) if (mat[i][j] == 'z') tld[i][j] = tld[i + 1][j - 1] + 1;
        }
        rep (i, 1, n) {
            rep (j, 1, m) {
                int r = j + tr[i][j] - 1;
                if (j <= r) segs[r].push_back({i, j});
            }
        }
    }
    
    struct BIT {
        lli seq[MAXN];
        #define lb(x) ((x) & (-(x)))
        void mo(int x) {
            for (; x <= m; x += lb(x)) ++seq[x];
        }
        lli qr(int x) {
            int r = 0; for (; x; x -= lb(x)) r += seq[x]; return r;
        }
    } diagonals[MAXN << 1];
    
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n >> m;
        rep (i, 1, n) cin >> (mat[i] + 1);
        pre();
        lli ans = 0;
        for (int j = m; j >= 1; --j) {
            for (auto seg : segs[j]) {
                int x = seg.fi, y = seg.se;
                diagonals[x + y].mo(y);
            }
            for (int i = 1; i <= n; ++i) {
                // (i, j) as the upperright corner
                if (mat[i][j] != 'z') continue;
                int maxlen = std::min(tl[i][j], tld[i][j]);
                int ql = j - maxlen + 1, qr = j;
                ans += diagonals[i + j].qr(qr) - diagonals[i + j].qr(ql - 1);
            }
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    F

    需要网络流相关知识

  • 相关阅读:
    大数据-数据分析-numpy库-数组的深拷贝和浅拷贝
    windows环境下mysql主从配置
    C#定时发送邮箱设置
    论《LEFT JOIN条件放ON和WHERE后的区别》
    记录成长
    RobotFramework+Selenium如何提高脚本稳定性
    Jekins 插件Extended Choice Parameter显示Json Parameter Type遇到的问题
    nGrinder 参数使用
    Jenkins REST API 实例
    java ee config / nacos / shit Alibaba Middleware
  • 原文地址:https://www.cnblogs.com/handwer/p/15473802.html
Copyright © 2011-2022 走看看