首页 > 其他分享 >The 2022 ICPC Asia Nanjing Regional Contest IGDA,和令人疑惑的M

The 2022 ICPC Asia Nanjing Regional Contest IGDA,和令人疑惑的M

时间:2024-10-19 21:42:42浏览次数:1  
标签:ch Contest int sum Regional cin Nanjing ++ --

I - 完美回文

题意

把单词改成一串相同的字母,最小修改次数

思路

把所有字母改成这个单词中出现次数最多的字母

代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
    string s;
    map<char, int> mp;
    cin >> s;
    int mx = 0;
    for (char ch : s) {
        mp[ch]++;
        mx = max(mx, mp[ch]);
    }
    cout << s.size() - mx << '\n';
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

G - 邪恶铭刻

题意

按顺序有三种情况

1获取野兽,攻击力为1
-1合成两只野兽
0选择1或-1

求最后野兽的平均战力最高是多少

思路

贪心的考虑0应该怎么分配

由于算的是平均值,合成野兽的贡献比增加野兽的贡献大,那么尽量选-1,只剩一只野兽的时候再选1

但是如果出现\(1,1,1,0,-1,-1,\) 这种序列,遇到0取-1是无法完成所有事件的

那么可以把0位置记录下来,一旦碰到无法完成所有任务的情况,就把0从-1改成1

代码

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

void solve() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int &i : a) cin >> i;
    int cnt = 0;
    int p = 1, q = 1;
    for (int i = 0; i < n; i++) {
        if (a[i] == 1) {
            p++;
            q++;
        } else if (a[i] == -1) {
            if (q > 1) {
                q--;
            } else {
                if (cnt) {
                    p++, q++;
                    cnt--;
                } else {
                    cout << -1 << endl;
                    return;
                }
            }
        } else {
            if (q > 1) {
                q--;
                cnt++;
            } else {
                p++, q++;
            }
        }
    }
    int z = __gcd(p, q);
    cout << p / z << " " << q / z << endl;
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) solve();
    return 0;
}

D - 聊天程序

题意

给初始序列 \(a\),要求最大化 \(a\) 的第 \(k\) 大的数

可以对 \(a\) 进行如下操作,给定等差数列的长度\(m\),首项\(c\),公差\(d\)

选择 \(a\) 的连续序列,把等差数列加上去

最多加1次

思路

采用二分第k大的值

关键在于check函数怎么写

暴力就是枚举每个位置的 \(a_i\) 作为开头,加一遍后看看能不能满足第 \(k\) 大的数大于 \(x\)

即便是暴力方式,也不能每次新建一个数组来排序,我们选择用计数的方式

大于等于 \(x\) 的个数大于等于 \(k\) 说明满足要求(注意这里的第k大是指从大到小排序的第k个数字,不用去重

那么接下来思考优化,对于等差数列,我们先只观察一个位置 以\([1,1,4,5,1,4]\)为例

\(c=1,d=2,m=3\),那么数列就是\(1,3,5\)

假定二分的第k大的值是4,观察 \(a_4=1\) ,如果 \(a_4\) (下标从0开始)作为等差数列的第二项,是满足要求的

但是如果作为等差数列的第3项,加起来也比4大

那么枚举 \(a_2\) 为开头,从 \(a_2\) 到 \(a_4\) ,排除原本就大于4的值,现在对答案的贡献就是 \(a_4\) 位置的1个

枚举 \(a_3\) 为开头,从 \(a_3\) 到 \(a_5\),对答案的贡献还是 \(a_4\)

每个位置作为等差开头从而新增的大于 \(x\) 的数量加上原本就大于 \(x\) 的数量如果大于等于 \(k\),return true

差分维护

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'

const int N = 2e5 + 10;
int a[N];
int n, k, m, c, d;
int sum[N];
bool check(int x) {
    fill_n(sum, n + 1, 0);
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        if (a[i] < x) {
            int rk;
            if (d != 0) {
                if (x <= a[i] + c)
                    rk = 1;
                else
                    rk = (x - a[i] - c + d - 1) / d + 1;
                if (rk > m) continue;
                if (i - rk + 1 >= 0) sum[i - rk + 1]++;
                if (i - m >= 0) sum[i - m] -= 1;
            } else {
                if (x - a[i] - c <= 0) {
                    rk = 0;
                    sum[i]++;
                    if (i - m >= 0) {
                        sum[i - m] -= 1;
                    }
                }
            }
        } else {
            cnt++;
        }
    }

    for (int i = n - 1; i >= 0; i--) {
        sum[i] += sum[i + 1];
        if (cnt + sum[i] >= k) return 1;
    }

    return 0;
}

void solve() {
    cin >> n >> k >> m >> c >> d;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    int l = 0, r = 1e18;
    int ans = 0;
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid)) {
            l = mid + 1;
            ans = mid;
        } else
            r = mid - 1;
    }
    cout << ans;
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0);
    int t = 1;
    while (t--) {
        solve();
    }
    return 0;
}

A - 停停,昨日请不要再重现

题意

一个棋盘上站满了袋鼠,给操作序列,袋鼠跟随操作序列移动,如果跳出棋盘就移除

棋盘上有个洞,掉进洞的袋鼠也被移除

问最后剩下 \(k\) 只袋鼠的话,有多少可能的位置上有洞,每次棋盘上只有一个洞

思路

在没有洞的情况下,可以判断出最后剩下的袋鼠是一个固定的矩形部分\(n',m'\)

在有洞的情况下,可以看成 \(n'm'\) 固定,这样洞就有一个路径

并且洞的路径不会超,洞的路径与操作相反,L说明洞往右走

而如果洞的路径超了,说明袋鼠全都走出去了,判掉就行

也就是说,我们把洞的路径看成一个方形g,用[[二维差分]]维护一下

\(g[x][y]\) 表示在 \((x,y),(x-U,y-L)\) 这个矩形内的洞经过的格子数

用所有剩下的袋鼠 \(x-g[x][y]\) 就是剩余的袋鼠数

代码

代码抄袭参考这篇

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N = 1000 + 10;
int n, m, k;
int U, D, L, R, U_, D_, L_, R_;
bool st[N][N]; // stone,表示石头是否存在在这一格
int g[N][N];
string op;

void add(int x1, int y1, int x2, int y2) {
    // 去重,洞走过多次等同于走一次
    if (st[x1][y1]) return;
    st[x1][y1] = true;
    // 差分
    g[x1][y1]++;
    g[x2 + 1][y1]--;
    g[x1][y2 + 1]--;
    g[x2 + 1][y2 + 1]++;
}

void solve() {
    cin >> n >> m >> k >> op;
    // 左上角为坐标原点
    U_ = L_ = U = L = 1;
    R_ = R = m;
    D_ = D = n;
    memset(st, 0, sizeof st);
    memset(g, 0, sizeof g);

    // 确定边界
    for (char ch : op) {
        // 往左,说明左边两行不用了
        if (ch == 'L') L_++, R_++;
        if (ch == 'R') L_--, R_--;
        if (ch == 'U') U_++, D_++;
        if (ch == 'D') U_--, D_--;
        L = max(L, L_);
        R = min(R, R_);
        U = max(U, U_);
        D = min(D, D_);
    }

    // 无袋鼠剩余
    if (U > D || L > R) {
        // 如果k>0 不可能完成,反之,洞随便放
        if (k)
            cout << "0\n";
        else
            cout << n * m << endl;
        return;
    }

    // 统计袋鼠经过格子的情况
    int x = (D - U + 1) * (R - L + 1), cnt = 0;
    add(U, L, D, R);
    for (char ch : op) {
        // 往左,说明洞往右
        if (ch == 'L') L--, R--;
        if (ch == 'R') L++, R++;
        if (ch == 'U') U--, D--;
        if (ch == 'D') U++, D++;
        add(U, L, D, R);
    }

    // 二分前缀和
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            g[i][j] += g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1];
        }
    }

    // 统计答案
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (x - g[i][j] == k) cnt++;
        }
    }

    cout << cnt << endl;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
}

M - 清空水箱

题意

逆时针给一个简单图形,没有交叉和重合,但是有共线的,这个图形是个水箱,里面有水,要开若干个洞才能把水全排出去

疑惑

题解还是挺多的,但是我有个wa30的思路表示十分疑惑,希望有佬能帮我看看哪里有问题

如图,逆时针的话,前一条边的极角是 \(a1\) ,后一条边是 \(a2\),用 \(atan2\) 函数来算

只要满足 \(a1>0\),\(a2>0\) ,\(a1>a2\)就说明需要开口

代码

#include <bits/stdc++.h>
using namespace std;
#define ld long double
#define endl '\n'
const double eps = 1e-7;
struct P {
    int x, y;
} a[2010];

void solve() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i].x >> a[i].y;
    }
    a[n].x = a[0].x;
    a[n].y = a[0].y;
    a[n + 1].x = a[1].x;
    a[n + 1].y = a[1].y;
    n++;
    int ans = 0;
    for (int i = 1; i < n; i++) {
        long double a1 = atan2l(a[i - 1].y - a[i].y, a[i - 1].x - a[i].x);
        long double a2 = atan2l(a[i + 1].y - a[i].y, a[i + 1].x - a[i].x);
        if (a1 > eps && a2 > eps) {
            if (a2 <= a1) ans++;
        }
    }
    cout << ans << endl;
}
int t = 1;
int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    while (t--) {
        solve();
    }
    return 0;
}

标签:ch,Contest,int,sum,Regional,cin,Nanjing,++,--
From: https://www.cnblogs.com/lulaalu/p/18486634

相关文章

  • The 2024 ICPC Asia East Continent Online Contest (II)打题+写题笔记
    前言方队让我们来打于是来打。赛时2h过了AFGIJL,感谢qsq贡献的G。评价:A:唐,F:唐,G:没看,I:小清新构造,J:国王游戏,L:不做评价。补题补了C,EEEscape链接题意给你\(n\)个波特和一个人与一张无向联通图,波特有一个共同的活动距离\(d\)。不能在原地不动。问人在保证不遇到波特的情况下......
  • AtCoder Beginner Contest 371 - VP记录
    总体发挥还算正常A-Jiro呵呵呵,有人像我这么做的吗?点击查看代码#include<cstdio>usingnamespacestd;intmain(){ charab,ac,bc; scanf("%c%c%c",&ab,&ac,&bc); if(ab=='<'&&ac=='<'&&bc=='<')......
  • C - Word Ladder (Toyota Programming Contest 2024#9 (AtCoder Beginner Contest 370)
    题目链接:C-WordLadder题目:样例:分析:不要被题目所吓到,一切长题目都是纸老虎。题目大意就是给你两个字符串s和t,一次只能更换一个字母,求s变到t更换的次数,并输出每次更换一个字母后的最小字典序字符串。题意好理解,可以直接暴力,大力出奇迹。但是有没有更好的方法呢?既然问了......
  • The 2024 CCPC National Invitational Contest (Northeast) ADEJ
    The2024CCPCNationalInvitationalContest(Northeast)ADEJA.PaperWatering思路:有两种类型的操作,对一个数开根号或平方。平方没有什么问题,开根号由于是向下取整再平方就会产生不一样的数。那么做法也很简单了。对于一个数\(x\),\(k\)步,首先它能平方往后变\(k\)步,往前能......
  • HIAST Collegiate Programming Contest 2024(非完全题解)
    C题HZY做的,等他补题解//#pragmaGCCoptimize("O3,unroll-loops")//#pragmaGCCtarget("avx2,bmi,bmi2,lzcnt,popcnt")////如果在不支持avx2的平台上将avx2换成avx或SSE之一#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecon......
  • AtCoder Beginner Contest 374 (A-E)
    AtCoderBeginnerContest374(A-E)比赛链接A-Takahashisan2#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;voidShowball(){strings;cin>>s;intn=s.size();cout<<(s.substr(n-3)=="san"......
  • 【ICPC】The 2021 ICPC Asia Shanghai Regional Programming Contest I
    SteadilyGrowingSteam#动态规划#背包#枚举题目描述AliceenjoysplayingacardgamecalledSteadilyGrowingSteam(asknownasSGS).Inthisgame,eachplayerwillplaydifferentrolesandhavedifferentskills.Playersgetcardsfromthedeckandu......
  • 【ICPC】The 2021 ICPC Asia Shenyang Regional Contest J
    LuggageLock#搜索#枚举题目描述EileenhasabigluggageandshewouldpickalotofthingsintheluggageeverytimewhenA-SOULgoesoutforashow.However,iftherearetoomanythingsintheluggage,the4-digitpasswordlockontheluggagewill......
  • 【ICPC】The 2021 ICPC Asia Shanghai Regional Programming Contest G
    EdgeGroups#树形结构#组合数学#树形dp题目描述Givenanundirectedconnectedgraphofnnnverticesandn......
  • 【ICPC】The 2021 ICPC Asia Shanghai Regional Programming Contest H
    LifeisaGame#最小生成树#重构树#图论#贪心题目描述Agoodproblemshouldhaveaconcisestatement.Youaregivenanarrayaaaoflength......