【题解】ABC289 E-G

现在 ABC 的 G 竟然沦落到我都能做出来的地步了。

E.Swap Places

题目分析:

这个题初看可能不很好好做的样子,但是看到它的数据范围是个 O(n2) 随便跑的复杂度,所以直接让两个人从 1n 去走就好了。
就是一个类似 bfs 的过程,为了让复杂度对一些,要保证走过的点对不再走了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+5;
struct node{
	int len,x,y;
};
vector<int> g[N];
int dp[N][N],c[N];
int main(){
	int t;scanf("%d",&t);
	while(t--){
		int n,m;scanf("%d%d",&n,&m);
		for(int i=1; i<=n; i++){
			for(int j=1; j<=n; j++){
				dp[i][j] = -1;
			}
		}
		for(int i=1; i<=n; i++)	scanf("%d",&c[i]);
		for(int i=1; i<=m; i++){
			int from,to;scanf("%d%d",&from,&to);
			g[from].push_back(to);
			g[to].push_back(from);
		}
		queue<node> q;
		q.push({0,1,n});
		while(!q.empty()){
			node now = q.front();q.pop();
			if(dp[now.x][now.y]!=-1)	continue;
			dp[now.x][now.y] = now.len;
			for(int i : g[now.x]){
				for(int j : g[now.y]){
					if(c[i] != c[j]){
						q.push({now.len+1,i,j});
					}
				}
			}
		}
		printf("%d\n",dp[n][1]);
		for(int i=1; i<=n; i++)	g[i].clear();
	}
	return 0;
}

F.Teleporter Takahashi

题目分析:

对于一个点 (a,b) 关于 (x,y) 的对称点为:(2×xa,2×yb),所以我们可以考虑对于横纵坐标分开考虑。
首先可以发现,我们的对称不会改变原来的横纵坐标的奇偶性,所以如果给定的和目标点的横纵坐标奇偶性不同,则无解。
顺着这个思路手模一下就会发现,如果我们将 (a,b) 先对于 (c,d) 对称再对于 (c+1,d) 对称,那么我们得到的点的坐标就是:(a+2,b)
也就是说我们这样的操作可以使得横坐标加 2 而不影响纵坐标,所以同理可以得到减 2 的推法。
那么就使用这个加 2 和减 2 的操作去一点点弥补横纵坐标的差距就好了。
需要特判一下矩阵的横纵坐标只有一种的情况。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
vector<pair<int,int> > v;
int sx,sy,tx,ty,a,b,c,d;
void move(int x,int y){
	v.push_back({x,y});
	sx = 2 * x - sx;
	sy = 2 * y - sy;
}
int main(){
	scanf("%d%d%d%d",&sx,&sy,&tx,&ty);
	scanf("%d%d%d%d",&a,&b,&c,&d);
	if((sx - tx) % 2 != 0 || (sy - ty) % 2 != 0){
		printf("No\n");
		return 0;
	}
	if(a == b && sx != tx)	move(a,c);  //只能转一次,所以不行就不行了 
	if(c == d && sy != ty)	move(a,c);
	if(a == b && sx != tx){
		printf("No\n");
		return 0;
	}
	else if(sx != tx){
		while(sx > tx)	move(a+1,c),move(a,c);
		while(sx < tx)	move(a,c),move(a+1,c); 
	}
	
	if(c == d && sy != ty){
		printf("No\n");
		return 0;
	}
	else if(sy != ty){
		while(sy > ty)	move(a,c+1),move(a,c);
		while(sy < ty)	move(a,c),move(a,c+1);
	}
	
	printf("Yes\n");
	for(auto i : v)	printf("%d %d\n",i.first,i.second);
	return 0;
}

G.Shopping in AtCoder store

题目分析:

我们可以发现如果选定了某一个价格,那么能购买他的人一定是 b 数组从大到小排序后的一个前缀。
稍微手推一下式子,算一下贡献的话就可以得到,如果要对于每一个 Ci 单独求解,必须做到能快速维护区间加+求区间最大前缀和,看上去就不大好做。
那么就看看是不是有什么单调性啊:显然是有的。
当我们的 Ci 增大的时候,最优的价格一定是不升的,可以考虑计算 Ci 变化的贡献就可以显然证明了。
这也就是决策单调性了,用分治去求就可以 O(nlogn) 解决问题了。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5+5;
struct node{
	int pos,val;
}c[N];
int b[N],ans[N];
bool cmp(node a,node b){
	return a.val < b.val;
}
bool cmp2(int a,int b){
	return a > b;
}
void solve(int l1,int r1,int l2,int r2){
	if(l1 > r1 || l2 > r2)	return;
	int val = 0,pos = 0,mid = (l2 + r2)>>1;
	for(int i=l1; i<=r1; i++){
		int res = i * (b[i] + c[mid].val);
		if(res > val)	val = res,pos = i;
	}
	ans[c[mid].pos] = val;
	solve(l1,pos,l2,mid-1);solve(pos,r1,mid+1,r2);
}
signed main(){
	int n,m;scanf("%lld%lld",&n,&m);
	for(int i=1; i<=n; i++)	scanf("%lld",&b[i]);
	for(int i=1; i<=m; i++)	scanf("%lld",&c[i].val),c[i].pos = i;
	sort(b+1,b+n+1,cmp2);sort(c+1,c+m+1,cmp);
	solve(1,n,1,m);
	for(int i=1; i<=m; i++)	printf("%lld ",ans[i]);
	return 0;
}
posted @   linyihdfj  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示