ZONe Energy Programming Contest(ABC)

考试情况

T1大水题秒过
T2数学题,推个相似就行了但推了好久
T3就是做不对,以为题目像愚人节一样有什么坑,就跳了
T4用个数据结构搞一搞就行了,vector或者deque吧,总之难度不大,由于前两场ABC里有相似的题目,所以没有绕弯路
磕了1个小时T5,一无所获,一眼看上去几乎和2020普及组T4一模一样那是因为我少看了个条件,于是就以为把那个代码改一点细节就行了,改到比赛结束才看到最后一个条件

题解

C

只能选三个人
摆在第一行的就是我少看到的条件(一种植物)
可以用二分+状压解决此题
二分答案,将每个人五门学科状态压缩,大于二分答案的为1,否则为0,枚举三种状态,如果存在三种状态,使它们取或的结果为11111,那么答案就可行,改变左端点
否则改变右端点

code
#include<bits/stdc++.h>
using namespace std;
const int N=3010;
int a[N][6],n;
bool check(int x)
{
	bool f[33]={0};
	for(int i=1;i<=n;i++)
	{
		int s=0;
		for(int j=0;j<5;j++)
			if(a[i][j]>=x)
				s|=(1<<j);
		f[s]=1;
	}
	for(int i=0;i<32;i++)
		for(int j=0;j<32;j++)
			for(int k=0;k<32;k++)
				if((i|j|k)==31&&f[i]&&f[j]&&f[k])
					return 1;		
	return 0;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) 
		for(int j=0;j<5;j++)
			cin>>a[i][j];
	int l=1,r=1e9,ans;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	cout<<ans;
	return 0;
}
E

完全和普及组的那道题不一样…
普及组的那道题是基于不能向左走,以及极大的数据范围,所以有了二维dp的做法
但这道题的数据范围不大,且四个方向都可以走(我没看见!)
所以这道题的正确做法为最短路
将二维图压成一维的点,根据题上所说前三个条件连边
最后一个条件的边是不容易连的(太多条了)
于是可以建一个双层图,假设原图为A层,新图为B层
将B层中向左走的每一步的代价都定义为1
然后假设从A层到B层的代价为1,从B层到A层的代价为0
这样就可以完美契合题中的最后一个条件
之后的跑个Dijkstra就好了

code
#include<bits/stdc++.h>
using namespace std;
const int N=5000010;
int r,c;
struct Star
{
	int to,nxt,val;
}edge[N];
int head[N],tot=0,dis[N],vis[N];
void Lian(int x,int y,int z)
{
	tot++;
	edge[tot].to=y;
	edge[tot].nxt=head[x];
	edge[tot].val=z;
	head[x]=tot;
}
struct Point
{
	int dd,p;
	bool operator<(const Point &x) const{
		return dd>x.dd;
	}
};
void dijkstra()
{
	for(int i=1;i<=2*r*c;i++) dis[i]=1e9;
	priority_queue <Point> que;
	dis[1]=0;
	Point a;
	a.p=1;
	a.dd=0;
	que.push(a);
	while(!que.empty())
	{
		a=que.top();
		que.pop();
		int x=a.p;
		if(vis[x]) continue;
		vis[x]=1;
		for(int i=head[x];i;i=edge[i].nxt)
		{
			int y=edge[i].to;
			if(dis[y]>dis[x]+edge[i].val)
			{
				dis[y]=dis[x]+edge[i].val;
				a.p=y;
				a.dd=dis[y];
				que.push(a);
			}
		}
	}
}
int main()
{
	cin>>r>>c;
	for(int i=1;i<=r;i++)
		for(int j=1;j<c;j++)
		{
			int a;
			cin>>a;
			Lian((i-1)*c+j,(i-1)*c+j+1,a);
			Lian((i-1)*c+j+1,(i-1)*c+j,a);
		}
	for(int i=1;i<r;i++)
		for(int j=1;j<=c;j++)
		{
			int a;
			cin>>a;
			Lian((i-1)*c+j,i*c+j,a);
		}
	for(int i=1;i<=r;i++)
		for(int j=1;j<=c;j++)
			Lian((i-1)*c+j,(i-1)*c+j+r*c,1),Lian((i-1)*c+j+r*c,(i-1)*c+j,0);
	for(int i=1;i<r;i++)
		for(int j=1;j<=c;j++)
			Lian(i*c+j+c*r,(i-1)*c+j+c*r,1);
	dijkstra();
	printf("%d",dis[r*c]);
	return 0;
}

总结

在家打可能没有状态吧,眼瞎导致了写不出来题…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值