Codeforces #479 (div 3)

Codeforces #479 (div 3)

补题链接

A. Wrong Subtraction

题意: 对一个数 x ,可以执行如下操作:

  • 最后一位非零,\(x= x - 1\)
  • 最后一位为0,\(x = x / 10\)

问执行k次操作后的值是多少。

题解: 模拟执行操作的过程。

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

int n, k;
int main()
{
    scanf("%d%d",&n,&k);
    while(k --){
        if(n % 10 == 0) n /= 10;
        else n -= 1;
    }
    printf("%d\n",n);
    return 0;
}

B. Two-gram

题意:给你一个字符串(仅含A-Z),将相邻两个字符的组合称为two-grams, 求出现次数最多的 two-grams

题解: 对每个字符组合进行哈希,考虑到组合数并不多,可以开一个num数组记录每个组合出现次数。在更新次数最大值maxx时顺便更新一下答案第二个字符的位置pos。

#include<bits/stdc++.h>
using namespace std;
const int N = 3e6 + 105;

int n, pos, num[N];
char s[N];

int main()
{
    scanf("%d",&n);
    scanf("%s",s + 1);
    int maxx = 0;
    for(int i = 2; i <= n; ++ i){
        int tp = ++ num[(s[i - 1] - 'A') * 30 + (s[i] - 'A')];
        if(tp > maxx){
            maxx = tp;
            pos = i;
        }
    }
    printf("%c%c\n",s[pos - 1], s[pos]);
    return 0;
}

C. Less or Equal

题意: 给一个大小为n的序列和一个数 k, 求一个数 x使得该序列中小于等于x的数的个数恰好为k。

题解: 将序列从小到大排序后,如果a[k] != a[k + 1] 就输出 a[k],否则输出 -1。注意特判 k = 0的情况:a[1] > 1时输出1,否则输出 -1。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;

int n, k;
ll a[N];

int main()
{
    scanf("%d%d",&n,&k);
    for(int i = 1; i <= n; ++ i) scanf("%lld",&a[i]);
    sort(a + 1, a + n + 1);
    if(k == 0){
        if(a[1] > 1) printf("1\n");
        else printf("-1\n");
        return 0;
    }
    if(a[k] != a[k + 1]) printf("%lld\n",a[k]);
    else printf("-1\n");
    return 0;
}

D. Divide by three, multiply by two

题意: 给大小为n的数组,要求重排这个数组,使得满足如下要求:如果第 i个数为 \(x​\) ,那第 i + 1 个数为 \(2x​\)\(x / 3​\) (x % 3 == 0时)。保证一定有解。

题解:

思路1:搜索,因为一定有解,所以可以固定第1个数,然后搜后面的数。

思路2:to[i]表示第 i 数后面放的数的位置,vis[i]表示第 i 个数前面的值有没有确定。从小到大排序,对每个数x,如果没有数在它前面,说明x/2没有在x前面,那只能试着把3x放在x前面,然后如果没有确定x后面的数,就试着把2x放在x后面。不考虑放x/3是因为x/3已经处理过了,肯定有放在它前面的值了。最后找一个前面没有值的数开始,沿着to[]数组的转移输出重排的序列。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 5;

int n;
ll a[N];
map<ll, int> mp;
int to[N], vis[N];
vector<int> res;

int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; ++ i) {
        scanf("%lld",&a[i]);
    }
    sort(a + 1, a + n + 1);
    for(int i = 1; i <= n; ++ i) mp[a[i]] = i;
    for(int i = 1; i <= n; ++ i){
        if(!vis[i]){
            ll tp = a[i] * 3;
            if(mp[tp]) {
                to[mp[tp]] = i;
                vis[i] = 1;
            }
        }
        if(!to[i]){
            ll tp = a[i] * 2;
            if(mp[tp]){
                to[i] = mp[tp];
                vis[mp[tp]] = 1;
            }
        }
    }
    for(int i = 1; i <= n; ++ i){
        if(vis[i]) continue;
        int tp = i;
        while(tp){
            res.push_back(tp);
            tp = to[tp];
        }
        break;
    }
    int tt = res.size();
    for(int i = 0; i < tt; ++ i){
        printf("%lld",a[res[i]]);
        if(i == tt - 1) printf("\n");
        else printf(" ");
    }
    return 0;
}

E. Cyclic Components

题意: 给n个点, m条边,求如下图这样环的个数。

题解: 可以发现,每个这样的环首先是一个联通块,而且联通块中每个点的度数为2。根据这一点我们用并查集找到所有联通块,如果一个联通块中度数都为2,res ++。最后res就是满足题意的环的个数。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 105;

int n, m, res;
int root[N], in[N], vis[N];

int Find(int x){
    return x == root[x] ? x : root[x] = Find(root[x]);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 0; i <= n; ++ i) root[i] = i;
    for(int i = 1; i <= m; ++ i){
        int x, y; scanf("%d%d",&x,&y);
        in[x] ++, in[y] ++;
        int tx = Find(x), ty = Find(y);
        if(tx != ty) root[tx] = ty;
    }
    for(int i = 1; i <= n; ++ i){
        if(in[i] != 2) vis[Find(i)] = 1;
    }
    for(int i = 1; i <= n; ++ i){
        if(root[i] == i && !vis[i]) res ++; 
    }
    printf("%d\n",res);
}

F. Consecutive Subsequence

题意: 给一个序列,求最长连续递增子序列。要求输出这个序列的长度和下标。

题解: dp转移很好想:\(dp[i] = max(dp[i], dp[mp[a[i] - 1]] + 1)​\) , 就是a[i]用前面最近的a[i - 1]更新。用p[]数组记录每个位置最后被前面哪个位置更新。假设dp[pos]最大,那就可以从pos沿着p[]数组一直向前把这个序列还原。注意还原过程是从后往前的,所以输出时要逆序输出。

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 105;

int n;
map<int, int>mp;
int dp[N], p[N];
vector<int> res;

int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; ++ i){
        int x; scanf("%d",&x);
        mp[x] = i;
        if(dp[mp[x - 1]] + 1 > dp[i]){
            dp[i] = dp[mp[x - 1]] + 1;
            p[i] = mp[x - 1];
        }
    }
    
    int maxx = 0, pos = 0;
    for(int i = 1; i <= n; ++ i){
        if(dp[i] > maxx){
            maxx = dp[i], pos = i;
        }
    }
    printf("%d\n",maxx);
    while(pos){
        res.push_back(pos);
        pos = p[pos];
    }
    int tt = res.size();
    for(int i = tt - 1; i >= 0; -- i){
        printf("%d",res[i]);
        if(i == 0) printf("\n");
        else printf(" ");
    }
    return 0;
}
posted @ 2020-09-10 15:15  长安大学ACM  阅读(114)  评论(0编辑  收藏  举报