考试情况
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;
}
总结
在家打可能没有状态吧,眼瞎导致了写不出来题…