2022 ICPC 济南区域赛题解 更新至 7 题(2022 International Collegiate Programming Contest, Jinan Site)

Preface

这场的C真的,让我脑细胞快死完了。

和张神推了快3个小时的dp,但是卡死在了最后的回退上。思考前后缀都无果,然后dp换了又换,最后终是燃尽了。

另外发现了个摸鱼G题。

我会在代码一些有必要的地方加上注释,签到题可能一般就不会写了.

以下是代码火车头:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <set>
#include <queue>
#include <map>
#include <unordered_map>
#include <iomanip>
#define endl '\n'
#define int long long
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rep2(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;

template<typename T>
void cc(const vector<T> &tem) {
    for (const auto &x: tem) cout << x << ' ';
    cout << endl;
}

template<typename T>
void cc(const T &a) { cout << a << endl; }

template<typename T1, typename T2>
void cc(const T1 &a, const T2 &b) { cout << a << ' ' << b << endl; }

template<typename T1, typename T2, typename T3>
void cc(const T1 &a, const T2 &b, const T3 &c) { cout << a << ' ' << b << ' ' << c << endl; }

void cc(const string &s) { cout << s << endl; }

void fileRead() {
#ifdef LOCALL
    freopen("D:\\AADVISE\\Clioncode\\untitled2\\in.txt", "r", stdin);
    freopen("D:\\AADVISE\\Clioncode\\untitled2\\out.txt", "w", stdout);
#endif
}

void kuaidu() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); }

inline int max(int a, int b) {
    if (a < b) return b;
    return a;
}

inline double max(double a, double b) {
    if (a < b) return b;
    return a;
}

inline int min(int a, int b) {
    if (a < b) return a;
    return b;
}

inline double min(double a, double b) {
    if (a < b) return a;
    return b;
}

void cmax(int &a, const int &b) { if (b > a) a = b; }
void cmin(int &a, const int &b) { if (b < a) a = b; }
void cmin(double &a, const double &b) { if (b < a) a = b; }
void cmax(double &a, const double &b) { if (b > a) a = b; }
using PII = pair<int, int>;
using i128 = __int128;
using vec_int = std::vector<int>;
using vec_char = std::vector<char>;
using vec_double = std::vector<double>;
using vec_int2 = std::vector<std::vector<int> >;
using que_int = std::queue<int>;

Problem A. Tower

也不知道哪个傻狗优先队列忘了清空WA了好几发。

这个题其实有点典,我们需要知道一个小trick,就是:如果一个数组里面,我们可以对任意一个数进行+1,或者-1的操作,问最少的操作次数变成同一个数字,那么最后变成的这个数字可以是他们中的中位数,这会是最少的操作次数之一。

那么加上/2的操作呢?

其实就是我们枚举的最终的数字的集合S里加上了每一个数字不停/2中间得到的数字,他们都有可能成为我们最终成为的数字。

这里的理解其实比较ez了,大概就是我们会先/2,/2,/2,然后再操作+和-的操作。如果我们一个数字先/2,再-1,-1,-1,再/2,其实不如我们/2,/2,再-1,-1这样快。

所以我们这里就把/2的操作转化成了枚举集合S。大小大概就是\(n*logn\),然后枚举每一个数字到达一个数字x,我们的复杂度有/2在,所以也是log级别的,复杂度就是\(n*log^2n\)

//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
// const int mod = 998244353;
const int INF = 1e16;
auto kuai = Kuai<mod>;
int n, m, T;
int A[N];

//--------------------------------------------------------------------------------
//struct or namespace:

//--------------------------------------------------------------------------------

int to(int x, int mid) {
    if (x == mid) return 0;
    if (x < mid) return mid - x;

    if ((x / 2) >= mid) return to(x / 2, mid) + 1;

    return min(x - mid, ((mid - (x / 2)) + 1));
}

signed main() {
    fileRead();
    kuaidu();
    T = 1;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        rep(i, 1, n) cin >> A[i];
        set<int> S;
        rep(i, 1, n) {
            int x = A[i];
            while (x) {
                if (S.count(x)) break;
                S.insert(x);
                x /= 2;
            }
        }
        priority_queue<int, vec<int>, greater<int>> F;

        int mmin = INF;

        for (auto mid : S) {

            while (!F.empty()) F.pop();

            int ans = 0;
            int sum = 0;

            rep(i, 1, n) {
                int tem = to(A[i], mid);
                ans += tem;
                F.push(tem);
                sum += tem;
                if (F.size() > m) {
                    sum -= F.top();
                    F.pop();
                }
            }
            cmin(mmin, ans - sum);
        }
        cc(mmin);



    }
    return 0;
}
/*


*/

Problem C. DFS Order 2

这个题真的,让我好一阵领教。感觉更加的厌恶dp了。

中间若干很多推理的细节让我感觉非常的爽但是又很恶心。

首先我们需要理解一个叫回退背包的东西(可逆背包),但是其实我们可以换一个思路去理解,和回退背包相比,我觉得就是一个dp,只不过思路没有怎么考虑到过。

一个小问题:01背包的问题下,一个背包有n个物品,每个物品有重量,有q次查询,每次查询是排除了物品x,剩余的组成重量大小m的方案数(无序)是多少。

我们该怎么思考这个问题呢?其实也是一个dp。

我们先跑一遍正常的背包

\[dp[j]+=dp[j-w] \]

倒序遍历后,这样\(dp[m]\)是我们的方案数。如何排除x呢?

\(f[x][j]\)是排除了x物品,组成大小j的方案数量。

则有:

\[f[x][j]=dp[j]-f[x][j-w] \]

\(w\)是物品x的重量,为什么会有这个式子呢?

不妨考虑一下,原本来说,我们有重量j的所有的方案,现在想要取消x,dp[j]里有装了x的部分,和没有装x的部分,考虑dp[j]里已经装了物品x的部分,那么这一部分的方案数,其实是等价于排除了x,重量组成j-w的方案数的。(毕竟x固定了,剩下的重量就是j-w,而且还是没有x,那这一部分就对应的是排除了x,重量组成j-w的方案数)。

也就是说等价于我们的\(f[x][j-w]\),所以我们正序遍历,保证用于运算的值都计算出来过了。

我们就求出来了排除了x,组成大小为j的数组,也就是刚才这个问题的ans。

有些代码是直接在dp上面做文章,但是说实在的我脑子不是太灵光,只能有这种方式去理解,从无序什么的角度去考虑个人感觉不如这个直接写一个dp直观一些。

有了以上的前提,我们就可以开始做这个题了(阿巴竟然才开始)

首先我们要考虑一个dp[i][j],代表第i个点在第j个位置出现的次数。

假设对于每一个父亲x和儿子y来说,x的dp数组全部已知,然后他们中间间隔了k个点的方案数是已知的,那么我们就可以推出来dp[y]的值。

我们设置f[j][k]代表大小是j,选择了k个点的方案数(无序)。

通过倒序遍历得到之后,我们就得到了对于当前点x的大小是j,选择了k个点的方案数。

然后后续我们就可以对于每一个他的儿子y去跑一个ex[j][k]数组,定义和f一样,但是去掉了当前儿子y,做法是我们上文提到的dp。

然后得到了之后,我们还要再设一个数组g[j],代表大小是j的方案数是多少(有序),由于这个要考虑有序,所以我们还要考虑到k的阶乘,因为选择了k个点,我们还需要考虑他们之间的组合,所以要乘上k的阶乘,还有是去掉了当前这个点和前面的k个点,后面的剩余的点的阶乘。

到现在为止,这个g数组就是我们上文说的,间隔了k个点的方案数。

\[dp[y][j]+=dp[x][j-k]*g[k-1]/(sum[x]!) \]

我们就可以写出来了这个式子。(sumx是x的儿子的个数)

x的方案数会有g[k-1]/(sum[x]!)分配到y的j里。

所以至此,按照我们上面说的内容,求出来dp数组,便是最后的答案了。

真的是一个又臭又长的dp啊。代码里有一点点的注释

//--------------------------------------------------------------------------------
const int N = 5e2 + 10;
const int M = 1e6 + 10;
// const int mod = 1e9 + 7;
const int mod = 998244353;
const int INF = 1e16;
auto kuai = Kuai<mod>;
int n, m, T;

//--------------------------------------------------------------------------------
//struct or namespace:

namespace nn {
    const int N = 1e5 + 10;
    vector<int> fact, infact;

    void clear() {
        fact.resize(N + 5);
        infact.resize(N + 5);
        fact[0] = infact[0] = 1;
        for (int i = 1; i < N; i++)  fact[i] = fact[i - 1] * i % mod;
        infact[N - 1] = Kuai<mod>(fact[N - 1], mod - 2);
        for (int i = N - 2; i >= 1; i--) {
            infact[i] = infact[i + 1] * (i + 1) % mod;
        }
    }

    int C(int n, int m) {
        if (n < m or m < 0) return 0;
        return fact[n] * infact[m] % mod * infact[n - m] % mod;
    }

}

namespace z {
    vector<PII> A[N];
    int son[N], dep[N];
    int val[N];

    int f[N][N], g[N][N], sum[N];
    int ex[N][N], dp[N][N];

    void dfs(const int x, const int pa) {
        son[x] = 1;
        dep[x] = dep[pa] + 1;

        val[x] = 1;

        for (auto [y, _] : A[x]) {
            if (y == pa) continue;
            dfs(y, x);
            son[x] += son[y];
            val[x] *= val[y];
            val[x] %= mod;
        }

        if (x != 1) sum[x] = A[x].size() - 1;
        else sum[x] = A[x].size();
        val[x] *= nn::fact[sum[x]];
        val[x] %= mod;

    }

    void dfs2(int x, int pa) {
        rep(i, 0, N - 1) rep(j, 0, N - 1) f[i][j] = 0;
        //f[j][k]:大小是j,选择了k个点的方案数
        f[0][0] = 1;
        for (auto& [y, _] : A[x]) {
            if (y == pa) continue;
            rep2(j, son[x], son[y]) {
                rep2(k, sum[x], 1) {
                    //val[x]:x的子树下的dfs序列的方案数
                    f[j][k] += f[j - son[y]][k - 1] % mod;
                    f[j][k] %= mod;
                }
            }
        }

        for (auto& [y, _] : A[x]) {
            if (y == pa) continue;

            rep(j, 0, n) {
                rep(k, 0, n) {
                    ex[j][k] = 0;
                }
            }

            rep(j, 0, son[x]) {
                rep(k, 0, sum[x]) {
                    if (j >= son[y] and k >= 1) {
                        ex[j][k] += (f[j][k] - ex[j - son[y]][k - 1] + mod) % mod;
                    }
                    else {
                        ex[j][k] += f[j][k];
                        ex[j][k] %= mod;
                    }
                    //ex[j][k]:大小j,选择了k个点,除去了y当前这个点
                    ex[j][k] += mod, ex[j][k] %= mod;
                }
            }

            static int ge[N];

            rep(j, 0, n) ge[j] = 0;

            rep(k, 0, sum[x] - 1) {
                rep(j, 0, son[x]) {
                    ge[j] += ex[j][k] * nn::fact[k] % mod * nn::fact[sum[x] - 1 - k] % mod;
                    ge[j] %= mod;
                }
            }

            rep(j, 1, n) {
                rep(k, 1, j) {
                    dp[y][j] += dp[x][j - k] * ge[k - 1] % mod * nn::infact[sum[x]] % mod;
                    dp[y][j] %= mod;
                }
            }


        }

        for (auto& [y, _] : A[x]) {
            if (y == pa) continue;
            dfs2(y, x);
        }


    }

    void clear(int n) {
        rep(i, 1, n) {
            A[i].clear();
        }
    }

    void add(int x, int y, int c = 1) {
        A[x].push_back({ y, c });
    }
};
//--------------------------------------------------------------------------------

signed main() {
    fileRead();
    kuaidu();
    T = 1;
    //cin >> T;
    while (T--) {
        cin >> n;
        z::clear(n);
        nn::clear();
        rep(i, 1, n - 1) {
            int a, b; cin >> a >> b;
            z::add(a, b);
            z::add(b, a);
        }
        z::dfs(1, 0);
        z::dp[1][1] = z::val[1];
        z::dfs2(1, 0);
        rep(i, 1, n) {
            int sum = 0;
            rep(j, 1, n) {
                int tem = z::dp[i][j];
                cout << tem << " ";
            }
            cout << endl;
        }

    }
    return 0;
}

/*


*/

Problem D. Frozen Scoreboard

不是吧真的有人会写大模拟吗?

sorry我会补的

Problem E. Identical Parity

一个中规中矩的小推理题。

首先我们知道,最后一定是长成(n/k)个长度是k的一模一样的区间A,和最后的n%k的区间B(这个区间是要和前面的区间的前缀一样的)。

一模一样的原因是因为,我们需要保证任意长度是k的区间都是奇偶性一样,只考虑0,1,像滑动窗口那样,每一次右边进入的一个数字,奇偶性要和左边出去的数字一样,滑动k次,我们就能发现这一点。所以我们就说这个是一模一样(仅用0,1去考虑)。

首先如果k是偶数,直接1010101这样就可以了,答案是YES。

k是奇数的情况下,我们1的个数可能和0一样,也可能多1。这是后续分类讨论的点。

先说前提:区间A指的是这些一模一样的区间中的其中一个,区间B是最后n%k的 区间。

我们可以知道A里一定要么1多,要么0多,因为k是奇数。

我们如果假设1的个数是a,0的个数是b,暂定a>=b,那么我们如果要成立,起码需要保证\((a-b)*k<=|B|\)(B的长度)

这样我们才能够在B区间去补回来少的那些0。

所以会发现,这个a-b的差值,越少越好,所以我们就规定A区间里,1的个数比0的个数多1。(因为奇数的个数大于等于偶数的个数,所以就想着奇数比偶数多1,没考虑偶数比奇数多的情况)

然后我们假设,区间B里,1的个数是a,0的个数是b,则有:

\[a+b=n\%k \\ a+n/k=b \\ a<=ceil(k/2) \\ b<=floor(k/2) \]

只要这些式子都是满足的,那么就说明是YES,否则是No。

后面这两个不等式的判断是因为,我们需要保证最后的区间B是和区间A的前缀一样的,也就是说B是A的子集才可以。

//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
//const int mod = 998244353;
const int INF = 1e16;
auto kuai = Kuai<mod>;
int n, m, T;

//--------------------------------------------------------------------------------
//struct or namespace:

//--------------------------------------------------------------------------------

signed main() {
    fileRead();
    kuaidu();
    T = 1;
    cin >> T;
    while (T--) {
        int k;
        cin >> n >> k;
        if (k % 2 == 0) {
            cc("Yes");
            continue;
        }
        if (n == k) {
            cc("Yes");
            continue;
        }
        if (n % 2 == 0) {
            if ((n / k) > (n % k)) {
                cc("No");
                continue;
            }
        }
        else {
            if ((n / k) - 1 > (n % k)) {
                cc("No");
                continue;
            }
        }

        int c;
        if (n % 2 == 1) c = n / k - 1;
        else c = n / k;

        if (((n % k) + c) % 2 == 0) {
            int x, y;
            y = ((n % k) + c) / 2;
            x = y - c;
            if (x <= ((k + 1) / 2) and y <= k / 2) {
                cc("Yes");
            }
            else {
                cc("No");
            }
        }
        else {
            cc("No");
            continue;
        }

    }
    return 0;
}

/*


*/

Problem G. Quick Sort

一个小弱智题,其实难度比C小好多,榜单歪了阿巴阿巴。

首先这个交换的复杂度是有些高的,如果每一次分出来的区间是1到n-1,n到n这种复杂度就会是\(O(n^2)\)

我们考虑一下优化,找的时候,我们的i其实是在找(i,n)区间内的第一个大于等于val的下标,j其实是在找(1,j)区间内的最后一个小于等于val的下标。

典典线段树呀。

维护线段树的节点信息有mmax和mmin(区间最大值和区间最小值)。

我们仅考虑i的情况,j和他很类似。

首先,线段树的qry函数(x,l,r,l1,r1,k)

x是当前节点编号,l,r是当前节点的l和r,l1和r1是我们要查询的区间,k是查询的值。

qry函数查询失败会返回-1.

如果我们的左儿子的最大值都小于了k的话,我们就直接查询右儿子吧。

如果最大值是大于等于l的话,就代表左儿子是有希望的,去查询一下。如果查询成功了就返回坐标,如果失败了,我们就再到右儿子去查询一下。

这就是大体思路,剩下的看代码吧。

//--------------------------------------------------------------------------------
const int N = 5e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
//const int mod = 998244353;
const int INF = 1e16;
auto kuai = Kuai<mod>;
int n, m, T;

//--------------------------------------------------------------------------------
//struct or namespace:
class SEG {
#define xl x+x
#define xr x+x+1

    //TODO 节点维护信息、apply函数、up函数
    struct info {
        int siz = 0;
        int mmax = -INF;
        int mmin = INF;
        int lan = 0;
        void apply(int k) {
            // siz += k;
            // mmax = k;
            // mmin = k;
        }

        void modify(int k) {
            siz = 1;
            mmax = k;
            mmin = k;
            // mmin = k;
            // you = 0;
            // siz = 1;
            // lan = 0;
        }

        friend info operator+(const info& q1, const info& q2) {
            info q;
            q.siz = q1.siz + q2.siz;
            q.mmax = max(q1.mmax, q2.mmax);
            q.mmin = min(q1.mmin, q2.mmin);
            // q.mmin = min(q1.mmin, q2.mmin);
            // if (q2.mmin == q1.mmin) q.you = min(q1.you, q2.you);
            // else {
            //     if (q1.mmin < q2.mmin) q.you = q1.you;
            //     else q.you = q2.you;
            // }
            return q;
        }
    };

    int L, R;
    info F[unsigned(N * 2.7)];

    void init(int x, int l, int r) {
        if (l == r) {
            F[x] = info();
            return;
        }
        int mid = l + r >> 1;
        init(xl, l, mid), init(xr, mid + 1, r);
        F[x] = F[xl] + F[xr];
    }

    void down(int x) {
        if (!F[x].lan) return;
        F[xl].apply(F[x].lan), F[xr].apply(F[x].lan);
    }

    void add(int x, int l, int r, int l1, int r1, int k) {
        if (l1 > r1) return;
        if (l != r) down(x);
        F[x].lan = 0;
        if (l1 <= l and r <= r1) {
            F[x].apply(k);
            return;
        }
        int mid = l + r >> 1;
        if (r1 <= mid) add(xl, l, mid, l1, r1, k);
        else if (mid < l1) add(xr, mid + 1, r, l1, r1, k);
        else add(xl, l, mid, l1, mid, k), add(xr, mid + 1, r, mid + 1, r1, k);
        F[x] = F[xl] + F[xr];
    }

    void modi(int x, int l, int r, int pos, int k) {
        if (pos < l or pos > r) return;
        if (l != r) down(x);
        F[x].lan = 0;
        if (pos == l and pos == r) {
            F[x].modify(k);
            return;
        }
        int mid = l + r >> 1;
        if (pos <= mid) modi(xl, l, mid, pos, k);
        else modi(xr, mid + 1, r, pos, k);
        F[x] = F[xl] + F[xr];
    }

    info qry(int x, int l, int r, int l1, int r1) {
        if (l1 > r1) return info();
        if (l != r) down(x);
        F[x].lan = 0;
        if (l1 <= l and r <= r1) return F[x];
        int mid = l + r >> 1;
        if (r1 <= mid) return qry(xl, l, mid, l1, r1);
        else if (mid < l1) return qry(xr, mid + 1, r, l1, r1);
        else { return qry(xl, l, mid, l1, mid) + qry(xr, mid + 1, r, mid + 1, r1); }
    }
    int get1(int x, int l, int r, int l1, int r1, int k) {
        if (l1 > r1) return -1;
        if (l == r) {
            if (F[x].mmax >= k) return l;
            else return -1;
        }
        int mid = l + r >> 1;
        if (r1 <= mid) return get1(xl, l, mid, l1, r1, k);
        else if (l1 >= mid + 1) return get1(xr, mid + 1, r, l1, r1, k);
        else {

            if (F[xl].mmax < k) return get1(xr, mid + 1, r, mid + 1, r1, k);
            int pos = get1(xl, l, mid, l1, mid, k);
            if (pos != -1) return pos;
            else return get1(xr, mid + 1, r, mid + 1, r1, k);
            // if (F[xl].mmax >= k) return get1(xl, l, mid, l1, mid, k);
            // else
        }
    }
    int get2(int x, int l, int r, int l1, int r1, int k) {
        if (l1 > r1) return -1;
        if (l == r) {
            if (F[x].mmax <= k) return l;
            else return -1;
        }
        int mid = l + r >> 1;
        if (r1 <= mid) return get2(xl, l, mid, l1, r1, k);
        else if (l1 >= mid + 1) return get2(xr, mid + 1, r, l1, r1, k);
        else {
            if (F[xr].mmin > k) return get2(xl, l, mid, l1, mid, k);
            int pos = get2(xr, mid + 1, r, mid + 1, r1, k);
            if (pos != -1) return pos;
            else return  get2(xl, l, mid, l1, mid, k);
            // if (F[xl].mmax <= k) return get2(xr, mid + 1, r, mid + 1, r1, k);
            // else return get2(xl, l, mid, l1, mid, k);
        }
    }
#undef xl
#undef xr

public:
    void clear(int l, int r) {
        L = l, R = r;
        init(1, l, r);
    }

    void add(int l, int r, int k) {
        cmax(l, L);
        cmin(r, R);
        add(1, L, R, l, r, k);
    }

    void modi(int pos, int k) { modi(1, L, R, pos, k); }

    info qry(int l, int r) {
        cmax(l, L);
        cmin(r, R);
        return qry(1, L, R, l, r);
    }

    int get1(int l, int r, int k) {
        // cmax(l, L);
        // cmin(r, R);
        return get1(1, L, R, l, r, k);
    }
    int get2(int l, int r, int k) {
        // cmax(l, L);
        // cmin(r, R);
        return get2(1, L, R, l, r, k);
    }
} seg;
int A[N];
//--------------------------------------------------------------------------------
int ans = 0;
int ddd(int* A, int l, int r) {
    int val = A[(l + r) / 2];
    int i = l - 1, j = r + 1;
    // int i = l, j = r;
    while (1) {
        // do {
        //     i++;
        // } while (A[i] < val);
        // do {
        //     j--;
        // } while (A[j] > val);
        // while (A[i] < val) i++;
        // while (A[j] > val) j--;
        i++, j--;
        // cc(1, j, val);
        i = seg.get1(i, n, val);
        j = seg.get2(1, j, val);
        // cc(j);
        // if(j==-1) 
        // if(i==-1 or j==-1)
        // cc(i, j, A[i], A[j]);
        if (j == -1) return 0;
        if (i == -1) return j;
        if (i >= j) return j;

        int q1 = seg.qry(i, i).mmax, q2 = seg.qry(j, j).mmax;
        seg.modi(i, q2);
        seg.modi(j, q1);
        swap(A[i], A[j]);
        ans++;
    }
}

void dfs(int* A, int l, int r) {
    if (l >= 0 and r >= 0 and l < r) {
        int x = ddd(A, l, r);
        dfs(A, l, x);
        dfs(A, x + 1, r);
    }
}

signed main() {
    fileRead();
    kuaidu();
    T = 1;
    cin >> T;
    while (T--) {
        cin >> n;
        seg.clear(1, n);
        ans = 0;
        rep(i, 1, n) {
            int a; cin >> a;
            A[i] = a;
            seg.modi(i, a);
        }
        // seg.modi(0, 0);
        dfs(A, 1, n);
        cc(ans);
    }
    return 0;
}

/*
5 9 9 1
9 8 9 2
1 8 4 2
2 5 8 1
3 4 6 3
4 3 6 3
1 2 2 1
2 1 2 1
2 2 2 2
5 8 8 4
6 7 7 5
7 6 7 5
4 5 6 4
5 4 6 4
5 6 6 5
6 5 6 5
7 7 7 7

*/

Problem K. Stack Sort

小弱智题,查询第i个数字要不要建stack只需要判断i+1有没有就好了。

//--------------------------------------------------------------------------------
const int N = 5e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
// const int mod = 998244353;
const int INF = 1e16;
auto kuai = Kuai<mod>;
int n, m, T;
int A[N];
bool fl[N];
//--------------------------------------------------------------------------------
//struct or namespace:

//--------------------------------------------------------------------------------

signed main() {
    fileRead();
    kuaidu();
    T = 1;
    cin >> T;
    while (T--) {
        cin >> n;
        rep(i, 0, n + 5) fl[i] = 0;
        int ans = 0;
        rep(i, 1, n) {
            cin >> A[i];
            fl[A[i]] = 1;
            if (fl[A[i] + 1] == 0) ans++;
        }
        cc(ans);

    }
    return 0;
}
/*


*/

Problem M. Best Carry Player

直接模拟就好了,但是写的有一点烂。

//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
// const int mod = 998244353;
const int INF = 1e16;
auto kuai = Kuai<mod>;
int n, m, T;
int A[N];

//--------------------------------------------------------------------------------
//struct or namespace:

//--------------------------------------------------------------------------------

signed main() {
    fileRead();
    kuaidu();
    T = 1;
    cin >> T;
    while (T--) {
        cin >> n;
        rep(i, 1, n) cin >> A[i];
        if (n == 1) {
            cc(0);
            continue;
        }

        int ans = 0;
        int las = 0;
        while (1) {
            bool fl = 0;
            int x = 0;
            rep(i, 1, n) {
                if (A[i] != 0) {
                    fl = 1;
                    x += A[i] % 10;
                    A[i] /= 10;
                }
            }
            x += las;
            ans += (x) / 10;
            las = x / 10;
            if (fl == 0) {
                while (las) {
                    x = 0;
                    x += las;
                    ans += (x) / 10;
                    las = x / 10;
                }
                break;
            }

        }
        cc(ans);

    }
    return 0;
}
/*


*/

PostScript

还是需要加训(吗?)

好懒,只想耍。没想到这学期比赛这么多,感觉拿一堆破铜烂铁回来给教练看,会gg。

posted @ 2025-05-02 15:59  AdviseDY  阅读(173)  评论(0)    收藏  举报