2018-2019, ICPC, Asia Yokohama Regional Contest 2018 (Gym - 102082)

2018-2019, ICPC, Asia Yokohama Regional Contest 2018

A - Digits Are Not Just Characters

签到。



B - Arithmetic Progressions

题意:从给定的集合中选出最多的数构成等差数列。

题解:数字排序后,设\(dp[i][j]\)表示等差数列最后一个数字为\(a[i]\),倒数第二个数字为\(a[j]\)的最大个数。然后对于每一位枚举 \(i\),\(lower\_bound()\)找有无合法的 \(j\) 即可。复杂度\(O(n^2log(n))\)。

代码:

#include <bits/stdc++.h>
#define fopi freopen("in.txt", "r", stdin)
using namespace std;
const int maxn = 5000 + 5;

int dp[maxn][maxn];
int a[maxn];
int n;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    sort(a+1, a+1+n);

    int ans = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j < i; j++) {
            int idx = lower_bound(a+1, a+1+n, a[j]-(a[i]-a[j])) - a;
            if (a[j] - a[idx] == a[i] - a[j])
                dp[i][j] = max(dp[i][j], dp[j][idx]+1);
            ans = max(ans, dp[i][j]);
        }
    printf("%d\n", ans+2);
}


C - Emergency Evacuation

题意:一些人在车座里,求所有人下车的最小时间。

题解:考虑到门口距离相等的两个人会在某个地方相遇,所以其中一个人要多花费一个单位的时间。故可以求出每个人到门口的距离,排序后处理相等的,直到序列变为升序。



D - Shortest Common Non-Subsequence

题意:给出两个\(01\)串\(s\)和\(t\),求最短的 \(01\) 序列,不是 \(s\) 和 \(t\) 的子序列。多组答案输出字典序最小的。

题解:序列自动机。预处理出\(s\)和\(t\)每个位置上后面第一个\(1\)和第一个\(0\)的位置。设当前在\(s\)和\(t\)的位置分别为\((x,y)\),则可以由\((next_s[x][1], next_t[y][1])\)和\((next_s[x][0],next_t[y][0])\)转移到,分别代表当前位放\(1\)和\(0\)。则答案就是从\((0,0)\)到\((len_s+1, len_t+1)\)的字典序最小的最短路。

代码:

#include <bits/stdc++.h>
#define fopi freopen("in.txt", "r", stdin)
#define fopo freopen("out.txt", "w", stdout)
using namespace std;
typedef long long LL;
const int maxn = 4000 + 5;
const int inf = 0x3f3f3f3f;

int dp[maxn][maxn], fa[maxn][maxn];
char s[maxn], t[maxn];
int nexta[maxn][2], nextb[maxn][2];
int l1, l2;
vector<int> ans;

int dfs(int x, int y) {
    if (x == l1+1 && y == l2+1) return 0;
    if (dp[x][y]) return dp[x][y];
    int tmp1 = dfs(nexta[x][0], nextb[y][0]),
        tmp2 = dfs(nexta[x][1], nextb[y][1]);
    if (tmp1 <= tmp2) fa[x][y] = -1; else fa[x][y] = 1;
    return dp[x][y] = min(tmp1, tmp2)+1;
}

void Print(int x, int y) {
    if (x == l1+1 && y == l2+1) return;
    int res = fa[x][y] > 0;
    ans.push_back(res);
    Print(nexta[x][res], nextb[y][res]);
}

int main() {
    scanf("%s%s", s+1, t+1);
    l1 = strlen(s+1), l2 = strlen(t+1);

    nexta[l1+1][1] = nexta[l1+1][0] = l1+1;
    nextb[l2+1][1] = nextb[l2+1][0] = l2+1;
    for (int i = l1; i >= 0; i--) {
        nexta[i][1] = nexta[i+1][1];
        nexta[i][0] = nexta[i+1][0];
        if (s[i+1] == '1') nexta[i][1] = i+1;
        else nexta[i][0] = i+1;
    }

    for (int i = l2; i >= 0; i--) {
        nextb[i][1] = nextb[i+1][1];
        nextb[i][0] = nextb[i+1][0];
        if (t[i+1] == '1') nextb[i][1] = i+1;
        else nextb[i][0] = i+1;
    }

    dfs(0, 0);
    Print(0, 0);

    for (auto p : ans) printf("%d", p);
    puts("");
}


E - Eulerian Flight Tour

题意:在一个图上任意添加一些边,使得图中存在欧拉回路。输出添加的边。

题解:

存在欧拉回路 \(=\) 所有点的度数为偶数。

把每条可用的边设为一个未知数(值为\(0\)或\(1\))。把每个点关于可用的边按度数写出一个方程,使得所有点的度数都为偶数。解非齐次线性方程组计算,计算出用哪些边(未知数值为1)。

若此时图已联通,那么这就是答案。如果此时图的连通块个数\(>=3\),可以加入一些边使它们成环。如果连通块的个数为\(2\),且每个连通块内都存在两点没有直接相连,那么就把这四个点连成环。

若方程组无解或无法联通,则无解。



G - What Goes Up Must Come Down

题意:通过交换相邻两个数的形式,把一个序列变为非递减\(+\)非递增两部分。求操作次数。

题解:小的数肯定要去大的外层。所以考虑每一个数走到两边的逆序对,每次取逆序对小的一侧。求和即为答案。求逆序对可以用树状数组,来回求两次。

代码:

#include <bits/stdc++.h>
#define fopi freopen("in.txt", "r", stdin)
#define fopo freopen("out.txt", "w", stdout)
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;

int n;
int a[maxn];
struct Trray {
    int C[maxn], N = 100000;
    void init() { memset(C, 0, sizeof(C)); }
    int lowbit(int x) { return x & (-x); }
    void update(int i, int k) {
        while(i <= N) C[i] += k, i += lowbit(i);
    }
    int getsum(int i) {
        int res = 0;
        while(i > 0) res += C[i], i -= lowbit(i);
        return res;
    }
}Tr;

int pre[maxn];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        Tr.update(a[i], 1);
        pre[i] = i - Tr.getsum(a[i]);
    }

    Tr.init();
    LL ans = 0;
    for (int i = n; i >= 1; i--) {
        Tr.update(a[i], 1);
        ans += min(pre[i], n-i+1 - Tr.getsum(a[i]));
    }
    printf("%lld\n", ans);
}


K - Sixth Sense

题意:你和对手都有\(n\)个数字。你可以任意改变自己的数字顺序,对于每个位置,若自己的数字大,则得一分。求保证得分最多的前提下,字典序最大的顺序方案。

题解:先贪心求出最大得分。然后从前往后枚举每个位置,二分当前位置,在不改变得分的前提下,可用的最大数字。注意当前位置要分为得分和不得分两种情况,分别二分(如果不分情况直接二分,例如敌方\(1\ 2\ 3\)/我方\(1\ 2\ 3\),第一局用\(1\)是会改变最大得分的,此时会被判定为不可以,\(mid\)会变小)。

代码:

#include <bits/stdc++.h>
#define fopi freopen("in.txt", "r", stdin)
using namespace std;
const int maxn = 5000 + 5;

int a[maxn], b[maxn], p[maxn];
int ans[maxn];
multiset<int> S, tep;
int n, x, num, now, tot;

bool check(int st, int mid) {
    int res = 0, id = 1;
    for (int i = st; i <= n; i++) {
        while(id == mid || (id <= tot && b[id] <= a[i])) id++;
        if (id <= tot) res++, id++;
    }
    return res + (b[mid] > a[st-1]) + now == num;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        p[i] = a[i];
    }

    for (int i = 1; i <= n; i++) {
        scanf("%d", &x);
        tep.insert(x);
        S.insert(x);
    }

    for (int i = 1; i <= n; i++) {
        multiset<int> :: iterator it = tep.upper_bound(a[i]);
        if (it == tep.end()) continue;
        if (*it > a[i]) num++, tep.erase(it);
    }

    for (int i = 1; i <= n; i++) {
        tot = 0;
        for (auto p : S) b[++tot] = p;

        copy(p+1, p+1+n, a+1);
        sort(a+i+1, a+1+n);

        int idx = upper_bound(b+1, b+1+tot, a[i])-b;
        int l = idx, r = tot, tmp = -1;
        while(b[idx] > a[i] && l <= r) {
            int mid = (l+r) / 2;
            if (check(i+1, mid)) tmp = mid, l = mid+1;
            else r = mid-1;
        }

        if (tmp == -1) {
            int l = 1, r = idx-1;
            while(l <= r) {
                int mid = (l+r) / 2;
                if (check(i+1, mid)) tmp = mid, l = mid+1;
                else r = mid-1;
            }
        }

        multiset<int> :: iterator it = S.lower_bound(b[tmp]);
        S.erase(it);

        if (b[tmp] > a[i]) now++;
        ans[i] = b[tmp];
    }

    for (int i = 1; i <= n; i++)
        printf("%d%c", ans[i], i == n ? '\n' : ' ');
}

原文地址:https://www.cnblogs.com/ruthank/p/11379269.html

时间: 2024-10-09 00:09:30

2018-2019, ICPC, Asia Yokohama Regional Contest 2018 (Gym - 102082)的相关文章

Asia Yokohama Regional Contest 2018 B题 - Arithmetic Progressions(dp)

https://codeforces.com/gym/102082 题意 给定一些数,可以重新排序,求其中最长的等差数列的长度 思路 d[i][j]表示以a[i]和a[j]为开头的等差数列的最大长度,具体见代码 1 #define bug(x,y) cout<<"i="<<x<<": "<<y<<endl 2 #define IO std::ios::sync_with_stdio(0); 3 #inclu

Asia Yokohama Regional Contest 2018 G题 What Goes Up Must Come Down(树状数组求逆序对)

https://codeforces.com/gym/102082 题意: 给一个数组大小不超过1e5,每个数的值也是1e5以内,可以交换相邻两个数,求保证它呈现一个非递减再非递增的趋势的最小交换次数. 题解: 对每个数来说,只有两种情况,要么参与非递减部分要么参与非递增部分,对于前者它要移的次数就是在它之前与他构成的逆序对数,对于后者它要移的次数就是在它之后与他构成的逆序对数,那我们取较小的加入到答案就做完了. #define bug(x,y) cout<<"i="<

【Asia Yokohama Regional Contest 2018】Arithmetic Progressions

题目大意:给定 N(1<N<=5000) 个不同元素组成的集合,求从中选出若干数字组成的等差数列最长是多少. 题解:直接暴力有 \(O(n^3)\) 的算法,即:枚举等差数列的前两个值,再暴力枚举后面的值进行匹配即可,不过这样做直接去世.. 考虑 \(dp[i][j]\) 表示以第 i 个数为数列倒数第二位,第 j 个数为等差数列中的最后一位的最长序列的长度,则:\(dp[i][j]=max\{dp[l][i]+1,a[i]-a[l]=a[j]-a[i]\&\&0<l&l

2018 ICPC Asia Jakarta Regional Contest

题目传送门 题号 A B C D E F G H I J K L 状态 Ο . . Ο . . . . Ο . . Ο Ο:当场 Ø:已补 .  :  待补 A. Edit Distance Thinking:kk pai爷 Code:kk 不能直接反转,比如"010101",直接反转后就变成"101010",右移一位,然后加个0就可以了. 所以要先统计01的数量,如果0大于1,就全变成1,1大于0,就全变成0(从数量上的改变就大于s/2了),相等的话,就看首位是0

2019-2020 ICPC, Asia Jakarta Regional Contest H. Twin Buildings

As you might already know, space has always been a problem in ICPC Jakarta. To cope with this, ICPC Jakarta is planning to build two new buildings. These buildings should have a shape of a rectangle of the same size. Now, their problem is to find lan

2019 ICPC Asia Yinchuan Regional

目录 Contest Info Solutions A. Girls Band Party B. So Easy D. Easy Problem E. XOR Tree F. Function! G. Pot!! H. Delivery Route I. Base62 K. Largest Common Submatrix N. Fibonacci Sequence Contest Info Practice Link Solved A B C D E F G H I J K L M N 9/1

The 2019 ICPC Asia Shanghai Regional Contest-B-Prefix Code

知识点:字典树. 题目链接: https://ac.nowcoder.com/acm/contest/4370/B 题意:t组数据,n个数字,问是否满足不存在任何一个数字是其他数字的前缀. 题解:套用字典树一个一个插入字符串.若在插入过程中遇到如下两种情况,则存在其中一个是另一个的前缀. 1.遍历完整个字符串都没有创造新的节点,说明该字符串是之前某个串的字串. 2.遍历过程中遇到了某个字符串的终点,说明存在一个字符串是该字符串的前缀. 若都不存在,则满足条件. AC代码: 1 #include

The 2019 ICPC Asia Shanghai Regional Contest---H Tree Partition 二分答案,从下往上切最大子树

题意:https://ac.nowcoder.com/acm/contest/4370 将一棵树切k-1刀分成k棵树,问这k棵树里最大的权值的最小值是多少 思路:https://www.cnblogs.com/ucprer/p/11931263.html 二分最大值. dfs割子树,每次从下往上切一个最大的树. 单个dfs表示保证当前节点可切,然后子树dfs完了,sort子树,选最大的切,直到当前u节点也可切 1 #define IOS ios_base::sync_with_stdio(0);

The 2019 ICPC Asia Shanghai Regional Contest-C-Spanning Tree Removal

知识点:构造.思维. 题目链接:https://ac.nowcoder.com/acm/contest/4370/D 题意:n点完全图,每次可以删除一个生成树的边,问最多可以删几次,并构造出其中一种. 题解:给出一种删边方式可以尽可能多次的删除:第i次:从i开始.依次删除i-(i+1)-(i-1)-(i+2)-(i-2)-…… 直到连接完所有点为止.总共可以删除n/2次. AC代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 i