Educational Codeforces Round 109 (Rated for Div. 2)(C,D)

C-Robot Collisions

题意:
(0~m) 的坐标轴上,机器人在碰到边界时会反向继续行走,已知(n)个机器人的初始位置和初始方向,每个机器人的速度为(1),问每个机器人在哪个时刻爆炸,机器人爆炸当且仅当两个机器人在整数点相遇。
思路:

  • 首先可以观察到只有机器人的初始位置的坐标的奇偶性相同时,才有可能发生碰撞,那么把问题分成两部分,奇坐标和偶坐标。
  • 对于某一可能碰撞部分,先将机器人按初始坐标排序,我们分两方面考虑,一方面是不需要转向的,对于不需要转向的,只有一种可能,即左边的向右边行走,右边的向左边行走。对于这一部分,我们可以用栈来维护,即向右边走的入栈,遇到向左边走的出栈,这样就可以保证正确性。
  • 另一方面,我们对于剩余的方向的(L)和方向为(R)的机器人,我们分别遍历,设(pos1<pos2),对于(L),我们按坐标从小到大遍历,对于相邻的两个机器人,其碰撞时刻一定是(pos1+(pos2-pos1)/2),对于(R),我们按坐标从大到小遍历,对于相邻的两个机器人,其碰撞时刻一定是(m-pos2+(pos2-pos1)/2)
  • 最后,方向(L)和方向(R)剩下的机器人最多都为(1),当两个都为(1)是,可以通过两个机器人都碰到边界后进行碰撞.

代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=300001;
const int INF=0x3f3f3f3f;

int n,m;
int a[MAXN];
int ans[MAXN];
map<int,int>mp;
char cc[MAXN];
struct node{
    int pos,dir;
}s[MAXN];
bool cmp(node xx,node yy)
{
    return xx.pos<yy.pos;
}
vector<node>v[2];
int main()
{
    int T;
    cin>>T;
    while(T--){
        v[0].clear();
        v[1].clear();
        mp.clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            mp[a[i]]=i;
            ans[i]=-1;
        }
        for(int i=1;i<=n;i++){
            getchar();
            scanf("%c",&cc[i]);
            v[a[i]%2].push_back((node){a[i],cc[i]=='L'});
        }
        for(int i=0;i<=1;i++){
            sort(v[i].begin(),v[i].end(),cmp);
            int cnt=0;
            for(int j=0;j<v[i].size();j++){
                if(v[i][j].dir==0)s[++cnt]=v[i][j];
                else{
                    if(cnt>0){
                        //cout<<i<<" "<<mp[s[cnt].pos]<<" "<<mp[v[i][j].pos]<<endl;
                        ans[mp[s[cnt].pos]]=(v[i][j].pos-s[cnt].pos)/2;
                        ans[mp[v[i][j].pos]]=(v[i][j].pos-s[cnt].pos)/2;
                        cnt--;
                    }
                }
            }
            // for(int i=1;i<=n;i++){
            //     printf("%d ",ans[i]);
            // }
            // cout<<endl;
            node lastl={0,0};
            for(int j=0;j<v[i].size();j++){
                if(v[i][j].dir==1&&ans[mp[v[i][j].pos]]==-1){
                    if(lastl.pos==0)lastl=v[i][j];
                    else{
                        //cout<<lastl.pos<<" "<<v[i][j].pos<<endl;
                        ans[mp[lastl.pos]]=lastl.pos+(v[i][j].pos-lastl.pos)/2;
                        ans[mp[v[i][j].pos]]=lastl.pos+(v[i][j].pos-lastl.pos)/2;
                        lastl=(node){0,0};
                    }
                }
            }
            // for(int i=1;i<=n;i++){
            //     printf("%d ",ans[i]);
            // }
            // cout<<endl;
            node lastr={0,0};
            for(int j=v[i].size()-1;j>=0;j--){
                if(v[i][j].dir==0&&ans[mp[v[i][j].pos]]==-1){
                    if(lastr.pos==0)lastr=v[i][j];
                    else{
                        //cout<<lastl.pos<<" "<<v[i][j].pos<<endl;
                        ans[mp[lastr.pos]]=m-lastr.pos+(lastr.pos-v[i][j].pos)/2;
                        ans[mp[v[i][j].pos]]=m-lastr.pos+(lastr.pos-v[i][j].pos)/2;
                        lastr=(node){0,0};
                    }
                }
            }
            // for(int i=1;i<=n;i++){
            //     printf("%d ",ans[i]);
            // }
            // cout<<endl;
            if(lastl.pos!=0&&lastr.pos!=0){
                ans[mp[lastl.pos]]=((m-lastr.pos)+lastl.pos+m)/2;
                ans[mp[lastr.pos]]=((m-lastr.pos)+lastl.pos+m)/2;
            }
        }
        for(int i=1;i<=n;i++){
            printf("%d ",ans[i]);
        }
        cout<<endl;
    }
}

D-Armchairs

题意:
(n)把椅子,至多有(n/2)个人坐在椅子上,问让所有有人坐的椅子都变空的最小代价是多少,坐在第(i)把椅子上的人移动到第(j)把椅子上的代价为 (abs(i-j))

思路:

  • 考虑(dp)(dp[i][j])表示让前(i)把椅子的人移动到前(j)把空椅子上的人的最小代价。
  • (dp)数组初始为(inf),可以推出转移方程 (dp[i+1][j]=min(dp[i][j],dp[i][j-1]+abs(pos[i]-pos[j-1])))

代码:

#include<bits/stdc++.h>
#define ll long long
#define MOD 998244353 
#define INF 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))  
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

vector<int>a,b;
int dp[5005][5005];  //表示前i个移动到j个空位置的最小花费
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int num;
		scanf("%d",&num);
		if(num==0)a.push_back(i);
		else b.push_back(i);
	}
	memset(dp,0x3f3f,sizeof dp);
	dp[0][0]=0;
	for(int i=0;i<a.size();i++){
		dp[i+1][0]=0;
		for(int j=1;j<=b.size();j++){
			int x=b[j-1];
			int y=a[i];
			dp[i+1][j]=min(dp[i][j],dp[i][j-1]+abs(x-y));
		}
	}
	cout<<dp[a.size()][b.size()]<<endl;
	return 0;
}
越自律,越自由
原文地址:https://www.cnblogs.com/ha-chuochuo/p/14778258.html