Codeforces Round #433 (Div. 2)( 模拟 + 思维 + 贪心 + dp )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ShadowGhostH/article/details/80177976

A

题意:给出一个真分数的分子分母的和n,求满足条件的最大的真分数。真分数为:分子小于分母且分子分母互质。gcd判断。

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

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

int main()
{

    int m, a, b;
    cin>>m;
    for(int i=1; i<=m/2; i++)
    {
        if(gcd(i, m-i)==1 && i!=m-i)
        {
            a = i;
            b = m-i;
        }
    }
    cout<<a<<" "<<b<<endl;
}

B

题意:给定n个房间,其中有m个房间有人,好房间的定义为:此房间没人,且是有人房间的隔壁。问好房间的最大和最小数量。

思路:我们可以知道一个有人的房间最多影响两个房间,那么当2*k>=n或3*k>=n时我们可知有人的房间可以将所有的房间都影响到,此时好房间就是n-k,其余时候好房间是2*k

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


const int maxn = 1e5+5;

int main()
{

    int n, k, minn, maxx;
    cin>>n>>k;

    if(k==0 || k==n) minn = maxx = 0;
    else {
        minn = 1;

        if(k*2>=n || 3*k>=n){
            maxx=n-k;
        }
        else {
            maxx=2*k;
        }
    }

    cout<<minn<<" "<<maxx<<endl;
}

C

题意:给出n个飞机,假定第i号飞机原定于第i分钟起飞,每延迟1分钟会有一定的花费。现给出前k分钟是没有飞机起飞的,且1分钟只能安排一架飞机起飞,而且每个飞机不能比原定起飞时间更早。问怎么安排飞机起飞可以得到最小花费。

思路:把这到题抽象成了打牌,前k分钟没有飞机起飞,也就是说我们在第k分钟起,手里有了k张牌,然后每回合打出一张。此时我们为使得花费最少,需要将每分钟花费增长最大的那个先打出去。优先队列模拟

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

const int maxn = 3e6+5;

struct Node{
    int id;
    int val;
    int tim;

    bool operator < (const Node &b) const{
        return val<b.val;
    }

}a[maxn];

priority_queue<Node> pq;

int main()
{
    cin.sync_with_stdio(false);

    int n, k;
    cin>>n>>k;

    for(int i=1; i<=n; i++)
    {
        cin>>a[i].val;
        a[i].id = i;
    }

    for(int i=1; i<=k; i++)
        pq.push(a[i]);

    int p = k+1;
    LL sum = 0;

    while(!pq.empty())
    {
        if(p<=n) pq.push(a[p]);

        Node now = pq.top();
        pq.pop();
        a[now.id].tim = p;
        sum += (LL)a[now.id].val*(p-now.id);

        p++;
    }

    printf("%I64d\n", sum);
    for(int i=1; i<=n; i++)
        printf("%d%c", a[i].tim, i==n?'\n':' ');

}

D

题意:有编号1~n的岛屿与0岛之间有航班,需要从n个岛选取代表去0号岛开一个为期k天的会议,到达和离开的当天不能开会,问如果能够在一起开会,输出最小花费,如果不能在一起开会输出-1

思路:和之前一个题目类似,我们将到达和离开分开考虑。用两个dp表示第i天所有人到达的最小花费和第i天所有人离去的最小花费,然后在枚举到达时间查找对应离开时间求解。

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

const int maxn = 1e5+5;
const int maxm = 1e6+5;
const int INF = 0x3f3f3f3f;
//const LL INF = 0x3f3f3f3f3f3f3f3f;

int vis[maxn];
LL come[maxm], go[maxm];

struct Node{
    int u, v;
    int day;
    LL cost;

    bool operator < (const Node &b) const{
        return day<b.day;
    }

}a[maxn];

int main()
{
    cin.sync_with_stdio(false);

    memset(come, 0, sizeof come);
    memset(go, 0, sizeof go);

//    for(int i=0; i<=10; i++)
//        printf("update %d: %lld\n", i, go[i]);

    memset(vis, -1, sizeof vis);

    int n, m, k, cnt, p;
    cin>>n>>m>>k;

    for(int i=0; i<m; i++)
        cin>>a[i].day>>a[i].u>>a[i].v>>a[i].cost;

    sort(a, a+m);

    cnt = n;
    LL best = 0;
    for(int i=0; i<m; i++)
    {

        //printf("*** %d %d %d %lld\n", a[i].day, a[i].u, a[i].v, a[i].cost);

        if(a[i].u == 0) continue;

        if(vis[a[i].u] == -1){
            cnt--;
            vis[a[i].u] = a[i].cost;
            best += a[i].cost;
        }

        else{
            if(vis[a[i].u] > a[i].cost)
            {
                best = best + a[i].cost - vis[a[i].u];
                vis[a[i].u] = a[i].cost;
            }
        }
        if(!cnt) {
            come[a[i].day] = best;
            //cout<<"Come: "<<a[i].day<<" "<<best<<endl;
        }
    }

    memset(vis, -1, sizeof vis);
    cnt = n;
    best = 0;

    for(int i=m-1; i>=0; i--)
    {
        if(a[i].u!=0) continue;

        if(vis[a[i].v] == -1){
            cnt--;
            vis[a[i].v] = a[i].cost;
            best += a[i].cost;
        }

        else{
            if(vis[a[i].v] > a[i].cost)
            {
                best = best + a[i].cost - vis[a[i].v];
                vis[a[i].v] = a[i].cost;
            }
        }
        if(!cnt) {
            go[a[i].day] = best;
            //cout<<"go: "<<a[i].day<<" "<<best<<endl;
        }
    }

    best = -1;

    for(int i=maxm-1; i>0; i--)
        if(go[i] == 0 && go[i+1] != 0) {
            go[i] = go[i+1];
            //printf("update %d: %lld\n", i, go[i]);
        }

    k++;

    for(int i=0; i+k<maxm; i++)
        if(come[i]!=0 && go[i+k]!=0)
            best = best==-1 ? come[i]+go[i+k] : min(best, come[i]+go[i+k]);

    cout<<best<<endl;
}

E

E题不会,暂留坑

猜你喜欢

转载自blog.csdn.net/ShadowGhostH/article/details/80177976