【Educational Codeforces Round 109 (Rated for Div. 2)】Codeforces-1525ABCD

A. Potion-making

e e + w = k 100 , ( k ∈ N )    ⟹    k 100 − k = e w \quad {e \over e+w} = {k \over 100} ,(k\in N)\implies {k \over 100-k} = {e \over w} e+we=100k,(kN)100kk=we,显然当k和(100-k)约到最简的时候总和是最小的

void solves(){
	int n;cin>>n;
	if(n==100){
		cout<<1<<endl;return ;
	} else{
		int m=100-n;
		int a=n/__gcd(n,m);
		int b=m/__gcd(n,m);
		cout<<a+b<<endl;
	}
}

B. Permutation Sort

一开始忘记考虑a[1]=n,a[n]=1的情况wa了一发

void solves(){
	int n;cin>>n;
	int f=0;
	for(int i=1;i<=n;++i){
		cin>>a[i];
		if(a[i]!=i)f=1;
	}
	if(!f){
		cout<<0<<endl;return ;
	}
	if(a[1]==n && a[n]==1){
		cout<<3<<endl;return ;
	}
	if(a[1]!=1&&a[n]!=n){
		cout<<2<<endl;
	} else cout<<1<<endl;
}

C. Robot Collisions

显然奇数坐标和偶数坐标要分开模拟
从左到右遍历所有的人。如果第二个机器人向左走,那么它必与第一个机器人相撞相消。如果第二个机器人向右走,那么我们标记它。
如果第三个机器人向左走。如果它的左边还有被标记(没被相消)的机器人,那么第三个机器人将会与被标记的最右边的机器人相撞。如果第三个机器人向右走,我们继续标记它…剩下的机器人以此类推。
显然我们可以利用后进先出的原则分别对奇偶坐标开一个栈来维护被标记的机器人。
如果最后还有未相消的、被标记的机器人,即栈不为空,那么相邻机器人之间的字母只可能是 R R或者R L。显然如果栈的长度是奇数,则栈尾的机器人不能消掉。我们再从右端(栈顶)遍历相消。

#define endl '\n'
const int N=3e5+7;
struct peo{
	int num,idx;char dir;
}a[N];
bool cmp(peo a,peo b){
	return a.num<b.num;
}
void solves(){
	int n,m;cin>>n>>m;
	vector<peo>a(n);
	for(int i=0;i<n;++i){
		cin>>a[i].num;
		a[i].idx=i;
	}
	for(int i=0;i<n;++i) cin>>a[i].dir;
	sort(a.begin(),a.end(),cmp);
	vector<int>ans(n+7,-1);
	vector<vector<int>>st(2);
	for(int i=0;i<n;++i){
		int f=a[i].num&1;
		if(st[f].size()){
			if(a[i].dir=='R'){ // X R
				st[f].push_back(i);continue;
			}
			int po=st[f].back();
			st[f].pop_back();
			char d=a[po].dir;
			if(d=='L'){ //L L
				int cc=(a[i].num+a[po].num)>>1;
				ans[a[i].idx]=ans[a[po].idx]=cc;
			} else ans[a[i].idx]=ans[a[po].idx]=abs(a[i].num-a[po].num)>>1; //R L
		} else{
			st[f].push_back(i);
		}
	}
	while(st[0].size()>1){
		int i=st[0].back();
		st[0].pop_back();
		int j=st[0].back();
		st[0].pop_back();
		if(a[i].dir==a[j].dir){  // R R
			ans[a[i].idx]=ans[a[j].idx]=(2*m-(a[i].num+a[j].num))>>1;
		} else{ //L R
			ans[a[i].idx]=ans[a[j].idx]=(2*m-abs(a[i].num-a[j].num))>>1;
		}
	}
	while(st[1].size()>1){
		int i=st[1].back();
		st[1].pop_back();
		int j=st[1].back();
		st[1].pop_back();
		if(a[i].dir==a[j].dir){  // R R
			ans[a[i].idx]=ans[a[j].idx]=(2*m-(a[i].num+a[j].num))>>1;
		} else{ //L R
			ans[a[i].idx]=ans[a[j].idx]=(2*m-abs(a[i].num-a[j].num))>>1;
		}
	}
	for(int i=0;i<n;++i){
		cout<<ans[i]<<" ";
	}cout<<endl;
}

D. Armchairs

计算前i个1移动到前j个0的最小花费。
取 第i个1移动到第j个0 和 第i个1不移动到第j个0 的最小距离。
状态转移方程 d p [ i ] [ j ] = m i n ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j − 1 ] + a b s ( b [ j − 1 ] − a [ i − 1 ] ) ) dp[i][j]=min(dp[i][j-1],dp[i-1][j-1]+abs(b[j-1]-a[i-1])) dp[i][j]=min(dp[i][j1],dp[i1][j1]+abs(b[j1]a[i1]))

void solves(){
	int n;cin>>n;
	vector<int>a,b;
	for(int i=1;i<=n;++i){
		int x;cin>>x;
		if(x)a.push_back(i);
		else b.push_back(i);
	}
	for(int i=0;i<=a.size();++i){
		for(int j=0;j<=b.size();++j) dp[i][j]=0x3f3f3f3f;
	}
	for(int j=0;j<=b.size();++j) dp[0][j]=0;
	for(int i=1;i<=a.size();++i){
		for(int j=1;j<=b.size();++j){
			dp[i][j]=min(dp[i][j-1],dp[i-1][j-1]+abs(b[j-1]-a[i-1]));
		}
	}
	cout<<dp[a.size()][b.size()]<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值