Educational Codeforces Round 109 (Rated for Div. 2)题解

C. Robot Collisions

题目:
There are n robots driving along an OX axis. There are also two walls: one is at coordinate 0 and one is at coordinate m.

The i-th robot starts at an integer coordinate xi (0<xi<m) and moves either left (towards the 0) or right with the speed of 1 unit per second. No two robots start at the same coordinate.

Whenever a robot reaches a wall, it turns around instantly and continues his ride in the opposite direction with the same speed.

Whenever several robots meet at the same integer coordinate, they collide and explode into dust. Once a robot has exploded, it doesn’t collide with any other robot. Note that if several robots meet at a non-integer coordinate, nothing happens.

For each robot find out if it ever explodes and print the time of explosion if it happens and −1 otherwise.

题意:
在一根坐标轴上,有 n n n个机器人,他们的速度相同均为1m/s,初始位置均不相同且在 0 0 0~ m m m之间,方向分别为向左或向右,他们会一直朝一个方向运动下去,直到他们在整数点上遇到其他的机器人(在非整数点相遇不会爆炸),这样它们都会爆炸并消失,或者遇到一面墙,这样它们就会转向继续运动。在坐标轴上,0和 m m m的位置都有一面墙,问他们会不会爆炸消失,如果消失输出他们消失的时间。

考察知识点:STL,排序

思路:
考虑到机器人如果消失,则最有可能会跟其相邻的机器人相遇,且两个机器人初始位置均为偶或奇。所以先将其全部排序,按照奇,偶分别建立一个deque(位置递增,且方向为右),按照下面的步骤加入进去:

  1. 若向右走,则直接加入deque中
  2. 若向左走,且deque不为空,则取出最右边的元素,计算两者相遇的时间
  3. 若向左走,且deque为空,则相当于其会在0处转向,实际上就相当于在坐标轴上的对称点向右走,所以将其位置取反加入deque中

最后按从deque的队尾中取出两个元素计算答案,直至deque的大小小于2

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int maxn=5110;
const int inf=0x3f3f3f3f;
int main()
{
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        vector<pair<pair<int,char> ,int> >vc(n);
        vector<int> ans(n,-1);
        for(int i=0;i<n;i++)
            cin>>vc[i].first.first;
        for(int i=0;i<n;i++)
            cin>>vc[i].first.second;
        for(int i=0;i<n;i++)
            vc[i].second=i;
        sort(vc.begin(),vc.end());
        deque<pair<int,int> > dq[2];
        for(auto x:vc){
            deque<pair<int,int> >&tmp=x.first.first%2?dq[1]:dq[0];
            if(x.first.second=='R'){
                tmp.push_back({x.first.first,x.second});
            }else{
                if(tmp.size()){
                    pair<int,int> qwq=tmp.back();
                    int val=qwq.first,id=qwq.second;
                    tmp.pop_back();
                    ans[id]=ans[x.second]=(x.first.first-val)/2;
                }else{
                    tmp.push_back({-x.first.first,x.second});
                }
            }
        }
        for(int i=0;i<2;i++){
            deque<pair<int,int> >&tmp=dq[i];
            while(tmp.size()>=2){
                pair<int,int> qwq=tmp.back();
                tmp.pop_back();
                pair<int,int> pwp=tmp.back();
                tmp.pop_back();
                ans[pwp.second]=ans[qwq.second]=(2*m-pwp.first-qwq.first)/2;
            }
        }
        for(auto x:ans)
            cout<<x<<" ";
        puts("");
    }
    return 0;
}

D. Armchairs

题目:
There are n armchairs, numbered from 1 to n from left to right. Some armchairs are occupied by people (at most one person per armchair), others are not. The number of occupied armchairs is not greater than n2.

For some reason, you would like to tell people to move from their armchairs to some other ones. If the i-th armchair is occupied by someone and the j-th armchair is not, you can tell the person sitting in the i-th armchair to move to the j-th armchair. The time it takes a person to move from the i-th armchair to the j-th one is |i−j| minutes. You may perform this operation any number of times, but these operations must be done sequentially, i. e. you cannot tell a person to move until the person you asked to move in the last operation has finished moving to their destination armchair.

You want to achieve the following situation: every seat that was initially occupied must be free. What is the minimum time you need to do it?

题意:
有n把椅子,初始有m个人坐在椅子上 ( 0 ≤ m ≤ n 2 ) (0\le m\le \frac{n}{2}) (0m2n),每次你可以让一个人离开现在的椅子 i i i去另一把椅子 j j j,这样做你将花费 ∣ i − j ∣ \lvert i-j\rvert ij,问让最初所有的m个人移动到一开始就没人的椅子的最小花费是多少

考察知识点:dp,预处理

思路:先预处理出所有初始有人的椅子 x [ ] x[] x[]和初始没人的椅子 y [ ] y[] y[],定义 f ( i , j ) f(i,j) f(i,j)为将前 j j j个人移动到前 i i i把椅子的最小花费,初始化所有 f ( i , j ) f(i,j) f(i,j)均为 i n f , f ( 0 , 0 ) = 0 inf,f(0,0)=0 inf,f(0,0)=0则转移方程为:
f ( i , j ) = m i n ( f ( i − 1 , j − 1 ) + ∣   y [ i ] − x [ j ]   ∣ , f ( i , j )   ) f ( i + 1 , j ) = m i n ( f ( i + 1 , j ) , f ( i , j )   ) ; f(i,j)=min(f(i-1,j-1)+\lvert \ y[i]-x[j]\ \rvert,f(i,j)\ )\\f(i+1,j)=min(f(i+1,j),f(i,j)\ ); f(i,j)=min(f(i1,j1)+ y[i]x[j] ,f(i,j) )f(i+1,j)=min(f(i+1,j),f(i,j) );
x [ ] x[] x[] y [ ] y[] y[]的长度为 t o t 1 , t o t 0 tot1,tot0 tot1,tot0,则最终的答案即为 f ( t o t 0 , t o t 1 ) f(tot0,tot1) f(tot0,tot1)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=5010;//
const int maxc=26;
const int base=131;
const int inf=0x3f3f3f3f;

int dp[maxn][maxn];
int x[maxn],y[maxn];

int main()
{
    int n;
    cin>>n;
    int tot0=0,tot1=0,tmp;
    for(int i=1; i<=n; i++)
    {
        cin>>tmp;
        if(tmp)
            x[++tot1]=i;
        else
            y[++tot0]=i;
    }
    memset(dp,inf,sizeof(dp));
    dp[0][0]=0;
    for(int i=0;i<=tot0;i++){
        for(int j=0;j<=i&&j<=tot1;j++){
            dp[i][j]=min(dp[i-1][j-1]+abs(y[i]-x[j]),dp[i][j]);
            dp[i+1][j]=min(dp[i+1][j],dp[i][j]);
        }
    }
    cout<<dp[tot0][tot1];
    return 0;
}

这题还有个最大流的做法:
考虑所有将源点与所有 x [ ] x[] x[]连边,将汇点与所有 y [ ] y[] y[]连边(边的容量均为1,花费均为0),再将所有相邻的椅子连边(边的容量为 i n f inf inf,花费为1),最后跑一遍最小费用最大流即可

E. Assimilation IV

待补充…

F. Goblins And Gnomes

待补充…

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值