Codeforces Round #318(ABCD)

A

题意:

每次操作可以让第一个数字加1,第一个数字之后的数字减1,问你最少变换多少可以使得第一个数字大于后面所有数字。

解析:

先保存下所有的数字,以及该数字出现的个数。
直接用map,每次取得map中最大的数字让这个数字的个数减去1,再把a[0]加一,在把这个最大的数字减去1,存入map中,直至a[0]大于所有的数字,输出最少的操作次数。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 1005;
int a[N], n;

map<int, int> mp;
map<int, int>::iterator it;

int main() {
    while(~scanf("%d", &n)) {
        mp.clear();
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
            if(i > 0) mp[a[i]]++;
        }

        it = mp.end(); it--;
        int ans = 0, maxa = it->first;
        while(a[0] <= maxa) {
            a[0]++; ans++;
            mp[maxa]--; mp[maxa-1]++;
            if(mp[maxa] == 0) it--;
            maxa = it->first;
        }
        printf("%d\n", ans);
    }
    return 0;
}

B

题意:

n个人,m个询问,然后接下来m行告诉你a与b是相互认识的,但是这个认识不能够相互传递,也就是说a认识b,b认识c,但是a并不认识c。

然后问你是否能够在这n个人中选取3个人,使得它们认识其他人的总数最少,并且这三个人要相互认识(也就是a-b,b-c,c-a),如果不存在则输出-1

解析:

枚举两条边判断这两条边能否构成三角形。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 4005;
struct Edge {
    int u[2];
} edge[N];

int n, m;
int deg[N];
bool G[N][N];

int check(int x, int y) {
    int ret = INF;
    int a, b, c, d;
    for(int i = 0; i < 2; i++) {
        for(int j = 0; j < 2; j++) {
            a = edge[x].u[i];
            b = edge[y].u[j];
            c = edge[x].u[i^1];
            d = edge[y].u[j^1];
            if(a == b && G[c][d]) {
                ret = deg[a] + deg[c] + deg[d] - 6;
                return ret;
            }
        }
    }
    return ret;
}

int cal() {
    int ret = INF;
    for(int i = 0; i < m; i++) {
        for(int j = i+1; j < m; j++) {
            ret = min(ret, check(i, j));
        }
    }
    return ret == INF ? -1 : ret;
}

int main() {
    int u, v;
    while(~scanf("%d%d", &n, &m)) {
        memset(deg, 0, sizeof(deg));
        memset(G, 0, sizeof(G));
        for(int i = 0; i < m; i++) {
            scanf("%d%d", &u, &v);
            if(v == u || G[u][v]) continue;
            G[u][v] = G[v][u] = true;
            deg[u]++, deg[v]++;
            edge[i] = (Edge){u, v};
        }
        printf("%d\n", cal());
    }
    return 0;
}

C

题意:

现在有n个人,每个人都持有a[i]这个价值的牌,并且每个人可以每次无限次数的使自己的牌扩大2倍,扩大3倍,然后问你是否可能使得最终所有人的牌的价值数变成一样的。

思路:

可以逆向思维,既然这些数字乘以无限多的2和3可以得到一样的数字,那么这些数字,不停的除以2与3,剩下的数字也可以通过不断的乘以2或者3得到。
所以我们可以使所有的数都不停的除以2与3,直到不能除为止,然后判断除完以后所有的数是否相同,如果相同,则说明是可以的,否则,则是不可以的。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = (int)1e5 + 10;
int a[N], n;

bool judge() {
    for(int i = 1; i < n; i++)
        if(a[i] != a[i-1])
            return false;
    return true;
}

int main() {
    while(~scanf("%d", &n)) {
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
        }
        for(int i = 0; i < n; i++) {
            while(a[i]%2==0) a[i]/=2;
            while(a[i]%3==0) a[i]/=3;
        }
        puts(judge() ? "Yes" : "No");
    }
    return 0;
}

D

题意:

有n个方格,然后每个方格都有一个高度,然后每次都可以把那些非完整块(就是它的四个方向没有被完全包围)给连在一起消去。问你最后把所有的方块消去需要几次。

解析:

就是求最高的 1, 2, 3, 4 …, 4, 3, 2, 1这样的等腰三角形的高度。

首先初始化为 L[0]=0,R[n+1]=0 ,我们设两个数组L代表的是从左边开始消去每次的最大高度,R则是右边的。

L[i]=min(h[i],L[i1]+1)
R[i]=min(h[i],R[i+1]+1)
ans=max(ans,min(L[i],R[i]))

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int h[N], L[N], R[N];
int n;

int main() {
    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d", &h[i]);
        }
        L[0] = R[n+1] = 0;
        for(int i = 1; i <= n; i++) {
            L[i] = min(L[i-1] + 1, h[i]);
        }
        for(int i = n; i >= 1; i--) {
            R[i] = min(R[i+1] + 1, h[i]);
        }
        int ans = 0;
        for(int i = 1; i <= n; i++) {
            ans = max(ans, min(L[i], R[i]));
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值