Codeforces掉分记 round318(div2)

Codeforces掉分记 round318(div2)

又升回紫名了2333,这一次就差一点点就AK了,还没有AK过。
(以下题目描述摘自codeforces)

A题 Bear and Elections

题目描述

Limak is a grizzly bear who desires power and adoration. He wants to win in upcoming elections and rule over the Bearland.

There are n candidates, including Limak. We know how many citizens are going to vote for each candidate. Now i-th candidate would get ai votes. Limak is candidate number 1. To win in elections, he must get strictly more votes than any other candidate.

Victory is more important than everything else so Limak decided to cheat. He will steal votes from his opponents by bribing some citizens. To bribe a citizen, Limak must give him or her one candy - citizens are bears and bears like candies. Limak doesn’t have many candies and wonders - how many citizens does he have to bribe?
Input
The first line contains single integer n (2 ≤ n ≤ 100) - number of candidates.

The second line contains n space-separated integers a1, a2, …, an (1 ≤ ai ≤ 1000) - number of votes for each candidate. Limak is candidate number 1.

Note that after bribing number of votes for some candidate might be zero or might be greater than 1000.

Output
Print the minimum number of citizens Limak must bribe to have strictly more votes than any other candidate.

题意

有N个候选人,每人有ai张选票,这个人要把别人的支持者收买过来,问最小费用。

解法

A题自古都是大水题,把选票存入优先队列里,每次收买选票最多的,最多收买10^5个。想了半天优美解法,结果交上去名次500+…

#include<bits/stdc++.h>

using namespace std;

int N;
int A[1005];

priority_queue<int> pq;

int main(){
    scanf("%d",&N);
    int now;
    scanf("%d",&now);
    for(int i=2;i<=N;i++){
        scanf("%d",&A[i]);
        pq.push(A[i]);
    }
    int res = 0;
    while(true){
        int pqtop = pq.top();
        if(pqtop < now) break;
        pq.pop();
        pq.push(pqtop - 1);
        res ++;
        now ++;
    }
    printf("%d\n",res);
    return 0;
}

B题 Bear and Three Musketeers

题目描述

Do you know a story about the three musketeers? Anyway, you will learn about its origins now.

Richelimakieu is a cardinal in the city of Bearis. He is tired of dealing with crime by himself. He needs three brave warriors to help him to fight against bad guys.

There are n warriors. Richelimakieu wants to choose three of them to become musketeers but it’s not that easy. The most important condition is that musketeers must know each other to cooperate efficiently. And they shouldn’t be too well known because they could be betrayed by old friends. For each musketeer his recognition is the number of warriors he knows, excluding other two musketeers.

Help Richelimakieu! Find if it is possible to choose three musketeers knowing each other, and what is minimum possible sum of their recognitions.

Input
The first line contains two space-separated integers, n and m (3 ≤ n ≤ 4000, 0 ≤ m ≤ 4000) — respectively number of warriors and number of pairs of warriors knowing each other.

i-th of the following m lines contains two space-separated integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi). Warriors ai and bi know each other. Each pair of warriors will be listed at most once.

Output
If Richelimakieu can choose three musketeers, print the minimum possible sum of their recognitions. Otherwise, print “-1” (without the quotes).

题意

有N个勇士,他们有一个关系网络,从中选取三个人,使他们互相认识并且这三个人认识的人数总和最少(他们三个之间除外)。

解法

简单搜索题,深搜出相连的三个勇士,再计算认识人数,每个勇士认识人数可以预处理。

小优化:避免查重可以按序号增序搜索。

#include<bits/stdc++.h>

using namespace std;

int N,M;
const int SIZE = 4005;
int know[SIZE];

set<int> S[SIZE];

struct P{
    int next,to;
}p[2*SIZE];
int head[SIZE];
int no;

void init(){
    memset(head,-1,sizeof(head));
    no = 0;
}

void add(int a,int b){
    p[no].to = b;
    p[no].next = head[a];
    head[a] = no++;
}

bool used[SIZE];
int fir;
int mid;
int res = 0x7fffffff;

void dfs(int u,int d){
    if(d == 2) mid = u;
    if(d == 3){
        if(S[u].find(fir) != S[u].end()){
            int temp = know[fir] + know[mid] + know[u] - 6;
            if(temp < res) res = temp;
        }
        return;
    }
    used[u] = true;
    for(int i = head[u]; i != -1; i = p[i].next){
        int v = p[i].to;
        if(used[v] || v < u) continue;
        dfs(v,d+1);
    }
    used[u] = false;
}

int main(){
    init();
    scanf("%d %d",&N,&M);
    while(M--){
        int a, b;
        scanf("%d %d", &a, &b);
        know[a]++;
        know[b]++;
        add(a,b);
        add(b,a);
        S[a].insert(b);
        S[b].insert(a);
    }
    for(fir = 1; fir <= N; fir++) dfs(fir,1);
    if(res == 0x7fffffff) printf("-1\n");
    else printf("%d\n",res);
    return 0;
}

C题 Bear and Poker

题目描述

Limak is an old brown bear. He often plays poker with his friends. Today they went to a casino. There are n players (including Limak himself) and right now all of them have bids on the table. i-th of them has bid with size ai dollars.

Each player can double his bid any number of times and triple his bid any number of times. The casino has a great jackpot for making all bids equal. Is it possible that Limak and his friends will win a jackpot?

Input
First line of input contains an integer n (2 ≤ n ≤ 105), the number of players.

The second line contains n integer numbers a1, a2, …, an (1 ≤ ai ≤ 109) — the bids of players.

Output
Print “Yes” (without the quotes) if players can make their bids become equal, or “No” otherwise.

题意

有N个数字,对每个数字可以进行两种操作(无限次):

1.将这个数乘2

2.将他乘3

问这N个数字是否可以变为相同的数字。

解法

显然这N个数字分别除掉他们的gcd对结果没有影响,假设可以变为相同的数字,设这个数字为P:

  • P = 2^i1 * 3^i2 * 5^i3 …
  • 显然,除了2和3以外,其他素因子的乘积一定是他们的gcd的因子

即每个数字除与他们的gcd后,他们的素因子只能有2和3.

#include<bits/stdc++.h>

using namespace std;

int N;
const int SIZE = 100005;
int A[SIZE];

int gcd( int a, int b )
{
    if( b == 0) return a;
    return gcd( b, a%b );
}

int gd;

bool sat(int n){
    while(!(n%2)) n /= 2;
    while(!(n%3)) n /= 3;
    if(n == 1) return true;
    return false;
}

bool solve(){
    for(int i = 1;i <= N; i++){
        if(!sat(A[i]/gd)) return false;
    }
    return true;
}

int main(){
    scanf("%d",&N);
    for(int i = 1; i <= N; i++){
        scanf("%d",&A[i]);
    }
    gd = A[1];
    for(int i = 2; i <= N; i++){
        gd = gcd(gd, A[i]);
    }
    if(solve()) puts("Yes");
    else puts("No");
    return 0;
}

D题 Bear and Blocks

题目描述

Limak is a little bear who loves to play. Today he is playing by destroying block towers. He built n towers in a row. The i-th tower is made of hi identical blocks. For clarification see picture for the first sample.

Limak will repeat the following operation till everything is destroyed.

Block is called internal if it has all four neighbors, i.e. it has each side (top, left, down and right) adjacent to other block or to the floor. Otherwise, block is boundary. In one operation Limak destroys all boundary blocks. His paws are very fast and he destroys all those blocks at the same time.

Limak is ready to start. You task is to count how many operations will it take him to destroy all towers.

Input
The first line contains single integer n (1 ≤ n ≤ 105).

The second line contains n space-separated integers h1, h2, …, hn (1 ≤ hi ≤ 109) — sizes of towers.

Output
Print the number of operations needed to destroy all towers.

cf318

题意

给N列方块,每次删掉边缘的方块,问要进行多少次操作将所有方块删掉。

解法

对于第 i 列方块,设使其消去的最小操作次数为f[i],那么有

  • f[i] = min(h[i], f[i-1] + 1, f[i + 1] + 1)

由此递推关系得出:

  • f[i] = min(h[i],min(h[i-1]+1, f[i-2] + 2, f[i] + 2), min(h[i+1]+1, f[i+2]+2, f[i]+2))
  • = min(h[i],h[i-1]+1,f[i-2]+2,h[i+1]+1,f[i+2]+2)
  • = min(h[i],
    h[i-1]+1,…,h[i-j]+j,h[2]+N-1,f[1]+N,
    h[i+1]+1,…,h[i+k]+k,h[N-1]+N-1,f[N]+N)
  • f[1] = f[N] = 1

这样就可以从左到右、从右到左遍历两边数组,得到f[i],f[i]的最大值即是答案。

#include<bits/stdc++.h>

using namespace std;

int N;
const int SIZE = 100005;
int A[SIZE];
int res[SIZE];

int main(){
    scanf("%d",&N);
    for(int i=1;i<=N;i++){
        scanf("%d",&A[i]);
        res[i] = A[i];
    }
    int now = 0;
    for(int i=1;i<=N;i++){
        int temp = now + 1;
        now = res[i] = min(res[i],temp);
    }
    now = 0;
    for(int i=N;i>=1;i--){
        int temp = now + 1;
        now = res[i] = min(res[i],temp);
    }
    int ans = 0;
    for(int i=1;i<=N;i++)
        if(ans < res[i]) ans = res[i];
    printf("%d\n",ans);
    return 0;
}

E题 Bear and Drawing

题目描述

Limak is a little bear who learns to draw. People usually start with houses, fences and flowers but why would bears do it? Limak lives in the forest and he decides to draw a tree.

Recall that tree is a connected graph consisting of n vertices and n - 1 edges.

Limak chose a tree with n vertices. He has infinite strip of paper with two parallel rows of dots. Little bear wants to assign vertices of a tree to some n distinct dots on a paper so that edges would intersect only at their endpoints — drawn tree must be planar. Below you can see one of correct drawings for the first sample test.

Is it possible for Limak to draw chosen tree?

Input
The first line contains single integer n (1 ≤ n ≤ 105).

Next n - 1 lines contain description of a tree. i-th of them contains two space-separated integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi) denoting an edge between vertices ai and bi. It’s guaranteed that given description forms a tree.

Output
Print “Yes” (without the quotes) if Limak can draw chosen tree. Otherwise, print “No” (without the quotes).

这里写图片描述

题意

给你无限长的两排点,问是否可以画出题目所给的树(不能有交叉).

解法

我先定义这几种树:
1. N-TREE :有N个单链的(儿子节点数等于这个子树的叶子节点数)
这里写图片描述
2. X-TREE:(随意命名的- -)就是叶子节点数大于儿子节点数的数
可以发现:以任意节点为根(设这个点为u),以u的子节点为根的子树最多只能有2个X-TREE、M-TREE(M>2),其余都必须为叶子、1-TREE、2-TREE。

这样就可以用搜索来解决,对于一个固定的有两个X-TREE、M-TREE(M>2)子节点的根,其余节点最多只能有一个(X-TREE、M-TREE(M>2))的子节点。

先用一边dfs找到这个点,如果没有,显然输出yes,找到后再进行一遍dfs看是否满足条件

(虽然是O(N)的算法,但是感觉还是有点挫,希望批评指正)

#include<bits/stdc++.h>

using namespace std;

int N;

const int SIZE = 100005;

struct P{
    int next,to;
}p[2*SIZE];
int head[SIZE];
int no;

void init(){
    memset(head,-1,sizeof(head));
    no = 0;
}

void add(int a,int b){
    p[no].to = b;
    p[no].next = head[a];
    head[a] = no++;
}

int used[SIZE];
bool haveans = true;
int st = -1;

int dfs(int u){
    used[u] = true;
    bool islef = true;
    int chd = 0;
    int cnt = 0;
    int sat = 0;
    for(int i=head[u];i!=-1;i=p[i].next){
        int v = p[i].to;
        if(used[v]) continue;
        islef = false;
        int temp = dfs(v);
        if(temp == 1) cnt++;
        if(temp <= 2) sat++;
        chd++;
    }
    if(islef) return 1;
    if(chd - sat > 2) haveans = false;
    else if(chd - sat > 1 && u != st) haveans = false;
    if(chd == cnt) return cnt;
    else return 10000;
}

bool used1[SIZE];

int dfs1(int u){
    used1[u] = true;
    bool islef = true;
    int chd = 0;
    int cnt = 0;
    int sat = 0;
    for(int i=head[u];i!=-1;i=p[i].next){
        int v = p[i].to;
        if(used1[v]) continue;
        islef = false;
        int temp = dfs1(v);
        if(temp == 1) cnt++;
        if(temp <= 2) sat++;
        chd++;
    }
    if(islef) return 1;
    if(chd - sat > 1) st = u;
    if(chd == cnt) return cnt;
    else return 10000;
}

int main(){
    scanf("%d",&N);
    init();
    for(int i = 1; i < N; i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }

    dfs1(1);
    if(st < 0){
        puts("Yes\n");
        return 0;
    }
    //printf("st=%d\n",st);
    dfs(st);
    if(haveans) printf("Yes\n");
    else printf("No\n");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值