ICPC 2019 陕西省赛

L. Digit Product

题目大意

定义f(x)为各个位数之积,给定lr,求 $ \prod_{i=l}^{r} f(i) \mod (10^9 + 7)$

解题思路

简单观察可以发现,只有数位中有0答案就是0,所以最多只会跑9个数字,遇到0剪枝退出即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const int MOD = 1e9 + 7;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        i64 l, r, ans = 1;
        std::cin >> l >> r;

        for (int i = l; i <= r && ans; i++) {
            std::string s = std::to_string(i);
            for (auto ch : s) {
                ans = (ans * (ch - '0')) % MOD;
                if (ans == 0) {
                    break;
                }
            }
        }

        std::cout << ans << "\n";
    }
}

F. K-hour Clock

题目大意

定义一天是k小时(k-1的下一个时刻为0),给定当前时间x,y小时后是z点,输出任意一个满足的k,不可能则输出-1

解题思路

分类讨论x+y和z的关系即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const int MOD = 1e9 + 7;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        i64 x, y, z, ans;
        std::cin >> x >> y >> z;

        if (z > x + y) {
            ans = -1;
        } else if (z == x + y) {
            ans = z + 1;
        } else {
            ans = x + y - z;
            if ((x + y) % ans != z || ans <= x) {
                ans = -1;
            }
        }

        std::cout << ans << "\n";
    }
}

E. Turn It Off

题目大意

给定长为n的01串,可以选择k次长为l的区间将1变为0,问最短的l是多少

解题思路

二分这个区间长度即可,特判全是1的情况

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const int MOD = 1e9 + 7;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, k;
        std::cin >> n >> k;

        std::string s;
        std::cin >> s;

        if (!std::count(s.begin(), s.end(), '1')) {
            std::cout << 0 << "\n";
            continue;
        }

        auto check = [&](int x) -> bool {
            int cnt = 0;
            for (int i = 0; i < n; i++) {
                if (s[i] == '1') {
                    i += x - 1;
                    cnt++;
                }
            }
            return cnt <= k;
        };

        int l = 1, r = n, ans = 0;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (check(mid)) {
                ans = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }

        std::cout << ans << "\n";
    }
}

B. Grid with Arrows

题目大意

给你两个n*m的矩阵ab,\(a_{ij}\)表示在该位置的移动方向,\(b_{ij}\)表示在该位置的移动距离,问是否存在一个位置使得从该位置出发可以遍历整个矩阵

解题思路

将每个格子视作一个节点,根据方向和距离建有向图,从入度最小的点开始dfs即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const int MOD = 1e9 + 7;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, m, x = 0;
        std::cin >> n >> m;

        std::vector<std::string> a(n);
        std::vector<std::vector<int>> b(n, std::vector<int>(m)), c(n, std::vector<int>(m)), g(n * m);
        std::vector<int> in(n * m), vis(n * m);

        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                std::cin >> b[i][j];
                c[i][j] = x++;
            }
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (a[i][j] == 'l' && j - b[i][j] >= 0 && j - b[i][j] < m) {
                    g[c[i][j]].push_back(c[i][j - b[i][j]]);
                    in[c[i][j - b[i][j]]]++;
                } else if (a[i][j] == 'r' && j + b[i][j] >= 0 && j + b[i][j] < m) {
                    g[c[i][j]].push_back(c[i][j + b[i][j]]);
                    in[c[i][j + b[i][j]]]++;
                } else if (a[i][j] == 'u' && i - b[i][j] >= 0 && i - b[i][j] < n) {
                    g[c[i][j]].push_back(c[i - b[i][j]][j]);
                    in[c[i - b[i][j]][j]]++;
                } else if (a[i][j] == 'd' && i + b[i][j] >= 0 && i + b[i][j] < n) {
                    g[c[i][j]].push_back(c[i + b[i][j]][j]);
                    in[c[i + b[i][j]][j]]++;
                }
            }
        }

        int cnt = 0, st, minn = 2e9;
        auto dfs = [&](auto &&self, int u) -> void {
            if (!vis[u]) {
                vis[u] = 1;
                for (auto v : g[u]) {
                    self(self, v);
                }
                cnt++;
            }
        };

        for (int i = 0; i < n * m; i++) {
            if (in[i] < minn) {
                minn = in[i];
                st = i;
            }
        }

        dfs(dfs, st);

        if (cnt != n * m) {
            std::cout << "No\n";
        } else {
            std::cout << "Yes\n";
        }
    }
}

C. 0689

题目大意

给定一个只包含0689四种字符的字符串,对任意非空子串进行至多一次180度旋转(例如0689变6890),问最后能有多少个不一样的字符串

解题思路

首尾是00,88,69的子串删除首尾之后对答案没有影响,统计之后去掉即可,特判全是6或9的情况,翻转不会变,需要对答案-1

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        std::string s;
        std::cin >> s;

        std::vector<i64> a(10);
        for (auto ch : s) {
            a[ch - '0']++;
        }

        i64 ans = s.size() * (s.size() + 1) / 2 + 1;
        ans -= a[0] * (a[0] + 1) / 2;
        ans -= a[8] * (a[8] + 1) / 2;
        ans -= a[6] * a[9];

        if (a[6] == s.size() || a[9] == s.size()) {
            ans--;
        }

        std::cout << ans << "\n";
    }
}

J. Coolbits

题目大意

给定n个区间,选n个数字,求这些数字按位与的最大值

解题思路

直接从高位开始贪心的填,先看所有的数字是否能在这一位填1,如果可以则直接填,否则再判断每个数字这一位填0还是1

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const int MOD = 1e9 + 7;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, ans = 0;
        std::cin >> n;

        std::vector<i64> l(n), r(n), x(n);
        for (int i = 0; i < n; i++) {
            std::cin >> l[i] >> r[i];
        }

        for (int i = 30; i >= 0; i--) {
            int f = 1;
            for (int j = 0; j < n && f; j++) {
                if ((x[j] | (1 << i)) > r[j]) {
                    f = 0;
                }
            }

            if (f) {
                ans |= 1 << i;
                for (int j = 0; j < n; j++) {
                    x[j] |= 1 << i;
                }
            } else {
                for (int j = 0; j < n; j++) {
                    // 填上1之后在范围内并且这一位不填1后面全填1仍然在范围外,则这一位必须填1
                    if ((x[j] | (1 << i)) <= r[j] && (x[j] | ((1 << i) - 1)) < l[j]) {  
                        x[j] |= 1 << i;
                    }
                }
            }
        }

        std::cout << ans << "\n";
    }
}
posted @ 2025-05-03 16:56  udiandianis  阅读(38)  评论(0)    收藏  举报