A. [USACO18OPEN,Silver]Multiplayer Moo
解析:这题挺水的。
首先跑一个bfs求连通块,附上对应的连通块标号,大小,颜色(及数字)。对相邻的连通块连边。然后枚举选择的两个颜色,对这两种颜色的连通块再求一次连通块即可。
乍一看时间复杂度
O
(
m
2
c
n
t
)
O(m^2cnt)
O(m2cnt),其中cnt是连通块数目,m是颜色数目。而
c
n
t
,
m
<
=
25
0
2
cnt,m<=250^2
cnt,m<=2502,显然超时。
cnt是不能优化的,这是求连通块的时间代价。而枚举m时可以只枚举颜色数前50个大的,这样就过了。
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N=255,M=255*255;
map<int,int> mp;
int ans,n,cnt,con[N][N],a[N][N],col[M],siz[M],lsh[M],num,sum[M];
int dx[5]={-1,0,1,0},dy[5]={0,1,0,-1};
bool pos[M];
vector<int> son[M];
bool cmp(int x,int y) {
return sum[x]>sum[y];
}
void bfs(int x,int y) {
queue<pair<int,int> > q;
q.push(make_pair(x,y));
con[x][y]=++cnt;
col[cnt]=a[x][y];
siz[cnt]=1;
while(q.size()) {
int x=q.front().first,y=q.front().second;
q.pop();
for(int i=0;i<4;i++) {
int tx=x+dx[i],ty=y+dy[i];
if(!con[tx][ty]&&a[x][y]==a[tx][ty]) {
q.push(make_pair(tx,ty));
con[tx][ty]=cnt;
siz[cnt]++;
}
}
}
}
void bfs2(int x,int a,int b) {
int tot=siz[x];
queue<int> q;
q.push(x);
pos[x]=1;
while(q.size()) {
int x=q.front();q.pop();
for(int i=0;i<son[x].size();i++) {
int y=son[x][i];
if(!pos[y]&&y>0&&(col[y]==lsh[a]||col[y]==lsh[b])) {
q.push(y);
pos[y]=1;
tot+=siz[y];
}
}
}
ans=max(ans,tot);
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
scanf("%d",&a[i][j]);
if(!mp[a[i][j]]) {
mp[a[i][j]]=++num;
lsh[num]=num;
}
a[i][j]=mp[a[i][j]];
sum[a[i][j]]++;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
if(!con[i][j]) {
bfs(i,j);
ans=max(ans,siz[con[i][j]]);
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
for(int s=0;s<4;s++) {
int k=i+dx[s],l=j+dy[s];
int x=con[i][j],y=con[k][l];
if(x!=y) {
son[x].push_back(y);
son[y].push_back(x);
}
}
}
printf("%d\n",ans);
sort(lsh+1,lsh+1+num,cmp);
for(int i=1;i<=min(num,50);i++) {
for(int j=1;j<=min(num,50);j++) {
if(i==j) continue;
for(int k=1;k<=cnt;k++) pos[k]=0;
for(int k=1;k<=cnt;k++) {
if(!pos[k]&&(col[k]==lsh[i]||col[k]==lsh[j])) {
bfs2(k,i,j);
}
}
}
}
printf("%d",ans);
}
B. 1-04D. 膨胀的tyx
解析:一道中规中矩的搜索题。
显然只在给定的图中遍历,用(x,y,h,l)四元组表示状态,其中(h,l)表示在大的平面内的横纵坐标。从起点开始bfs,x>n则h++,x=0则h --;y>n则l++,y=0则l --。
当到达以前走过的点时,判断h,l是否相等,不相等则输出No;否则不加入队列(重复状态)。搜索结束后就输出Yes。
C. [树声前锋杯] E 小马过河
不会。
D. 2-04D. 懒得说话的tyx
解析:这道题我是用数位dp做的。
注意前导0,正常的数位dp中都用dfs中参数z表示是否有前导0,这里我把它拆分成f1和f2,f1没有前导零,f2有前导零。
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」