首页 > 其他分享 >The 2022 ICPC Asia Jinan Regional Contest

The 2022 ICPC Asia Jinan Regional Contest

时间:2023-10-06 14:12:31浏览次数:37  
标签:Regional return Contest int Jinan cin long vector using

A. Tower

首先用了 dp 验证出把一个数字变成另一个数字的最优解一定是能除就先进行除法,然后再使用加一减一。

这样我们就有\(O(\log n)\)的复杂度求出把一个数变成另一个数的最小代价。

然后就是猜测最终的目标一定是某个数除了若干次二得到的。所以就枚举一下目标即可。

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;

void solve() {
    int n, m;
    cin >> n >> m;
    set<int> tot;
    vector<int> a(n);
    for (int x; auto &i: a) {
        cin >> i, x = i;
        while (x) tot.insert(x), x /= 2;
    }
    auto calc = [](int x, int y) {
        if (y > x) return y - x;
        int cnt = 0;
        while (x / 2 > y) cnt++, x /= 2;
        return min(cnt + x - y, cnt + 1 + y - x / 2);
    };
    int res = LLONG_MAX;
    for( auto x : tot ){
        vi b;
        for( auto i : a )
            b.push_back( calc( i , x ) );
        sort( b.begin(), b.end() );
        res = min( res , accumulate(b.begin(), b.end() - m , 0ll) );
    }
    cout << res << "\n";
    return;
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int T;
    for (cin >> T; T; T--)
        solve();

    return 0;
}

D. Frozen Scoreboard

这题其实就是模拟,首先枚举出那些题是封榜后通过的,先假设题目的都是在 240 分钟时通过,然后先尽可能的使用 WA,如果 WA不能用是再尝试把通过时间向后调。

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, m;

using vi = vector<int>;
using vs = vector<string>;


vector<string> state;
vector<int> x, y;
vi unKnow;

int finalSolved, finalPenalty, frozenSolved;
int solved = 0, penalty = 0;
bool flag;

void check(vi v) {
    int pPenalty = penalty;
    auto sState = state;
    auto xX = x, yY = y;
    for (int i = 0, j; i < unKnow.size(); i++) {
        j = unKnow[i];
        if (v[i] == 1) {
            sState[j] = "+";
            xX[j] = y[j] - x[j] + 1;
            yY[j] = 240;
            pPenalty += (xX[j] - 1) * 20 + yY[j];
        } else {
            sState[j] = "-";
            xX[j] = y[j];
            yY[j] = 0;
        }
    }
    if (pPenalty > finalPenalty)
        return;
    for (int i = 0, j; i < unKnow.size(); i++) {
        if (v[i] == 0) continue;
        j = unKnow[i];
        while (xX[j] < y[j] and pPenalty + 20 <= finalPenalty) {
            pPenalty += 20, xX[j]++;
        }
    }
    for (int i = 0, j, t; i < unKnow.size(); i++) {
        if (v[i] == 0) continue;
        j = unKnow[i];
        t = min(59ll, finalPenalty - pPenalty);
        pPenalty += t, yY[j] += t;
    }
    if (pPenalty != finalPenalty) return;
    flag = true;
    state = sState, x = xX, y = yY;
    return;
}

void dfs(int i, vi v, int cnt) {
    if (flag == true) return;
    if (cnt == frozenSolved) {
        check(v);
        return;
    }
    if (i >= unKnow.size()) return;
    dfs(i + 1, v, cnt);
    v[i] = 1;
    dfs(i + 1, v, cnt + 1);
    v[i] = 0;
    return;
}

void solve() {
    cin >> finalSolved >> finalPenalty;
    solved = 0, penalty = 0;
    state = vs(m), x = vi(m), y = vi(m);
    unKnow = vi();

    for (int i = 0; i < m; i++) {
        cin >> state[i];
        if (state[i] == "+") {
            char s;
            cin >> x[i] >> s >> y[i];
            solved++, penalty += (x[i] - 1) * 20 + y[i];
        } else if (state[i] == "?") {
            cin >> x[i] >> y[i];
            unKnow.push_back(i);
        } else if (state[i] == "-") {
            cin >> x[i];
        }
    }

    if (solved > finalSolved or penalty > finalPenalty) {
        cout << "No\n";
        return;
    }

    if (solved + unKnow.size() < finalSolved) {
        cout << "No\n";
        return;
    }

    frozenSolved = finalSolved - solved;

    flag = false;

    dfs(0, vi(unKnow.size()), 0);

    if (flag == false) {
        cout << "No\n";
        return;
    }
    cout << "Yes\n";
    for (int i = 0; i < m; i++) {
        cout << state[i];
        if (state[i] == "+") {
            cout << " " << x[i] << "/" << y[i];
        } else if (state[i] == "-") {
            cout << " " << x[i];
        }
        cout << "\n";
    }
    return;
}

int32_t main() {
    cin >> n >> m;
    for (; n; n--)
        solve();
    return 0;
}

E. Identical Parity

为了方便表示,下述除法都是向下取整

首先可以知道的是如果为偶数时只要一奇一偶的放就好了。

然后考虑奇数的情况,首先数字的值其实无关紧要,只要知道奇偶性即可。所以我们把所有的数字都转换成 01 来表示。所以0的个数有$\frac n 2 \(个,1的个数有\)\frac n 2 + 1 $个。

然后考虑两个相邻的区间,我们可以知道的是每次变化的两个数的奇偶性相同

\[a_1=a_{1+k}=a_{1+2k}=\cdots\\ a_2=a_{2+k}=a_{2+2k}=\cdots\\ \vdots\\ a_k=a_{2k}=a_{3k}=\cdots \]

所以实际上序列被分成了\(k\)组,其中\(n\%k\)组有$\frac n k + 1 \(个元素,\)n-n%k\(组有\)\frac n k$个元素,并且每一组中元素都完全相同。

这样的话实际上我们从两种组面各选多少种全部赋值为 1,只要判断有没有解即可。

\[a=\frac n k + 1 , b = \frac n k , c = \frac n 2 + 1 \\ 0\le x \le n\%k, 0\le y\le n - n\%k\\ax+by=c \]

也就是说判断上述方程是否有解即可。可以先用扩偶解除特解,在根据通解公式判断是否有解。

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;
using db = long double;

constexpr int inf = 1E18;


int exgcd(int a, int b, int &x, int &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, x, y);
    int z = x;
    x = y;
    y = z - y * (a / b);
    return d;
}

void solve() {
    int n, k;
    cin >> n >> k;
    if( n == k and n == 1 ){
        cout << "Yes\n";
        return ;
    }
    if (k & 1) {
        if (k == 1) {
            cout << "No\n";
        } else {
            int a = n / k, b = (n + k - 1) / k, c = n / 2, x0, y0, d;
            d = exgcd(a, b, x0, y0);
            if (c % d != 0) {
                cout << "No\n";
                return;
            }
            int x = c / d * x0, y = c / d * y0, dx = b / d, dy = a / d;
            {
                int kk = (-x) / dx;
                x = x + kk * dx, y = y - kk * dy;
            }
            for (; y >= 0; x += dx, y -= dy) {
                if( x < 0 ) continue;
                if (n % k != 0 and x + y <= k and x <= k - n % k and y <= n % k) {
                    cout << "Yes\n";
                    return ;
                } else if (n % k == 0 and x + y <= k and min(x, y) == 0) {
                    cout << "Yes\n";
                    return ;
                }
            }
            cout << "No\n";
        }
    } else {
        cout << "Yes\n";
    }
    return;
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

可惜这样做太慢了,但是我们发现当\(k\)确定时,有解的 n 其实不多。打表可以发现,有解 n 是

k = 3 
n/k \ n%k	0	1	2
1			3	4	5
2				7

k=5
n/k \ n%k	0	1	2	3	4	
1			5	6	7	8	9
2				11	12	13	
3					17

k=7
n/k \ n%k	0	1	2	3	4	5	6
1			7	8	9	10	11	12	13
2				15	16	17	18	19
3					23	24	25
4						31

这样话,实际上可以\(O(1)\)的判断出对于当前的\(k\),\(n\)是否合法

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;

constexpr int inf = 1E18;

void solve() {
    int n, k;
    cin >> n >> k;
    if (n == k and n == 1) {
        cout << "Yes\n";
        return;
    }
    if (k % 2 == 0) {
        cout << "Yes\n";
        return;
    }
    if (k == 1) {
        cout << "No\n";
        return;
    }

    int t = n / k;
    int l = t * k, r = l + k - 1;
    l = l + t - 1, r = r - t + 1;
    if (l <= n and n <= r)
        cout << "Yes\n";
    else
        cout << "No\n";
    return;
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

K. Stack Sort

用 multiset 统计当前栈的结尾是啥

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;

void solve() {
    int n;
    multiset<int> s;
    cin >> n;
    for (int x; n; n--) {
        cin >> x;
        if (s.count(x + 1) > 0) {
            s.erase(s.lower_bound(x + 1));
        }
        s.insert(x);
    }
    cout << s.size() << "\n";
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

M. Best Carry Player

高精度模拟一下,统计进位次数就好了

#include <bits/stdc++.h>

using namespace std;

#define int long long

using vi = vector<int>;

void solve() {
    int n, len = 0;
    cin >> n;
    vector<string> num(n);
    for (auto &i: num) {
        cin >> i;
        reverse(i.begin(), i.end());
        len = max(len, (int) i.size());
    }
    vector<int> a(len + 1);
    int cnt = 0;
    for (int i = 0; i < len; i++) {
        for (auto s: num) {
            if (i >= s.size()) continue;
                a[i] += s[i] - '0';
        }
        a[i+1] = a[i] / 10 , a[i] %= 10;
        cnt += a[i+1];

    }


    while( a.back() >= 10 )
        cnt += a.back() / 10 , a.push_back( a.back() / 10 );
    cout << cnt << "\n";
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

标签:Regional,return,Contest,int,Jinan,cin,long,vector,using
From: https://www.cnblogs.com/PHarr/p/17744520.html

相关文章

  • The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online (The 2nd Universal Cup
    The2018ACM-ICPCAsiaQingdaoRegionalContest,Online(The2ndUniversalCup.Stage1:Qingdao)J-PresstheButton\(1\leqa,b,c,d\leq10^6\)题解容易发现存在循环节,每次位于\(gcd(a,c)\)的倍数的位置所以我们考虑处理一个循环节内的情况如果\(v\le......
  • AtCoder Grand Contest 036 F Square Constraints
    洛谷传送门AtCoder传送门本质是\(p_i\in[l_i,r_i]\)的计数问题。当\(1\lei\len\)时,\(l_i\)才可能不等于\(1\)。考虑容斥,设钦定\(m\)个不满足条件(上界为\(l_i-1\)),其余任意(上界为\(r_i\))。然后按照上界排序后dp,设\(f_{i,j}\)为考虑前\(i\)个元素,已经......
  • 2017 China Collegiate Programming Contest Final (CCPC-Final 2017)
    Preface今天打学校统一要求的这场CCPC2017Final,直接被打爆了,各种数学题搞得人生活不能自理主要是H徐神开场就秒出了正确的思路,然后一心认准高斯消元然后一直想+写+调到结束都没卡过去比赛最后20min的时候祁神想到了更好写的基于施密特正交化的方法,可以碍于时间有限没调出来不......
  • AtCoder Beginner Contest 288 Ex A Nameless Counting Problem
    洛谷传送门AtCoder传送门考虑到规定单调不降比较难搞。先设\(g_t\)为长度为\(t\)的满足条件的序列个数(可重且有顺序)。求这个可以设个dp,\(f_{d,i}\)表示考虑到从高到低第\(d\)位,当前\(t\)个数中有\(i\)个仍然顶上界,并且之前的位都满足异或分别等于\(X\)的限制。......
  • AtCoder Grand Contest 056 D Subset Sum Game
    洛谷传送门AtCoder传送门考虑若\(n\)是奇数怎么做。枚举Alice第一次选的数\(a_i\),然后考虑把剩下的数两两结成一个匹配,若Bob选了其中一个,Alice就选另一个。容易发现排序后奇数位和它右边的偶数位匹配最优。那么设奇数位的和为\(A\),偶数位的和为\(B\),此时Alice获胜......
  • AtCoder Beginner Contest 178 E
    AtCoderBeginnerContest178EE-DistMax曼哈顿距离最大点对\(ans=max(|x_i-x_j|+|y_i-y_j|)\)考虑去绝对值,4种情况。sort一下取max即可。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=2e5+10;intx[N],y[N];intp[4][N];......
  • 2022 China Collegiate Programming Contest (CCPC) Weihai Site
    PrefaceVP到自己学校出的题了可海星,不得不说学长们出的题比起昨天VP的CCPC2022广州做起来要舒服地多这场前面写题都很顺基本都是一发过,中期的medium也没怎么卡思路和卡机子,一道一道地慢慢出最后一个小时徐神RushF可惜没Rush出来,然后我和祁神坐在下面把B的做法给搞出来了,但不知......
  • The 2022 ICPC Asia Shenyang Regional Contest
    C.ClampedSequence因为\(n\)的范围不大,并且可以猜到\(l,r\)中应该至少有一个在\(a_i,a_i-1,a_i+1\)上。所以直接暴力枚举\(l\)或\(r\)然后暴力的计算一下#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongusingvi=vector<int>;int32_tmain(){......
  • AtCoder Beginner Contest 322
    A-FirstABC2解题思路签到Code#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;voidsolve(){ intn; cin>>n; strings; cin>>s; intp=s.find("ABC"); if(p==-1)cout<<p<<'\n&......
  • 2022 China Collegiate Programming Contest (CCPC) Guangzhou Onsite
    Preface好难啊这场广州站,不愧是5题金4题铜的超恶劣站,中档题普遍难度较高但我感觉主要原因还是题目出的太偏向于DP了,AI是本质差不多的树上换根DP,M又是个数位DP,导致像我这种不擅长DP的人直接中期坐牢但好在祁神大力切出了medium~hard的K题,然后最后一小时我把一直在想的A题丢给徐......