10.3 CSP B组模拟赛
写在前面:
至于10.3号的模拟为什么今天写。。。。这种事情不是很显而易见嘛。
我可是养鸽大户QAQ
其实这两天的题都还好,不算难。
T1 长方形
考试考结论以及数学对我来说最不友好了啊QAQ
鸡腿想到了一个很高(sha)明(bi)的问题,在 N 条水平线与 M 条竖直线构成的网格中,放 K 枚石子,每个石子都只能放在网格的交叉点上。问在最优的摆放方式下,最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。
对于你们来说,这种结论题简直显然。
但是我打完T2,T3之后一个多小时全在搞这个题,最后交了个暴力QAQ
结论:
能把点堆在一起就堆在一起。多出来的位置再单独计算。
那么这题我们只需要枚举能围城的边长,然后处理多出来的部分,就完事了。
代码
数学菜鸡跟着题解改了小一个小时QAQ
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,m,k,ans=0; int ad(int x,int y,int i) { return x*(x-1)/2*i*(i-1)/2+y*(y-1)/2*x; } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=2;i<=m;i++) { int x=k/i,y=k%i; if(x>n) continue; if(x==n&&y) continue; ans=max(ans,ad(x,y,i)); } for(int i=2;i<=n;i++) { int x=k/i,y=k%i; if(x>m) continue; if(x==m&&y) continue; ans=max(ans,ad(x,y,i)); } cout<<ans<<endl;; return 0; }
T2 连通块
这题简直友好啊友好。
Alice为了***难你,拆掉编号从l到r的边,当然你需要做的事情就是求连通块的个数。
不记得在哪次集训的时候讲过的一种思想了,还好还记得。
运用类似分块的思想【可能是我太喜欢分块了QAQ
把图中的点看作3部分:
1. l前
2. r后
3. l~r
那么如果要是想要求出 除了l~r 的信息,那不就是只求第一和第三部分的结果吗?
很显然,我们可以很轻松的通过预处理的方法求出任意位置x的1~x和x~n的结果。
询问的答案就是使用预处理的答案,fa[l-1]与fa[r+1]的值进行合并。
那么显然这就是一个二维并查集维护连通块个数的问题了。
代码来啦
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,m,k; struct ss{ int l,r; }d[100007]; int a[510],fa[10007][510],ba[10007][510]; int fi_fa(int id,int x) { if(fa[id][x]==x) return x; return fa[id][x]=fi_fa(id,fa[id][x]); } int fi_ba(int id,int x) { if(ba[id][x]==x) return x; return ba[id][x]=fi_ba(id,ba[id][x]); } int fi_a(int x) { if(a[x]==x) return x; return a[x]=fi_a(a[x]); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&d[i].l,&d[i].r); for(int i=1;i<=n;i++) { fa[0][i]=i; ba[m+1][i]=i; } for(int i=1;i<=m;i++) { memcpy(fa[i],fa[i-1],sizeof fa[i]); int col_x=fi_fa(i,d[i].l); int col_y=fi_fa(i,d[i].r); if(col_x!=col_y) fa[i][col_x]=col_y; } for(int i=m;i>=1;i--) { memcpy(ba[i],ba[i+1],sizeof ba[i]); int col_x=fi_ba(i,d[i].l); int col_y=fi_ba(i,d[i].r); if(col_x!=col_y) ba[i][col_x]=col_y; } scanf("%d",&k); while(k--) { int l,r; scanf("%d%d",&l,&r); memcpy(a,fa[l-1],sizeof a); for(int i=1;i<=n;i++) { int col_x=fi_a(a[i]); int col_y=fi_a(ba[r+1][i]); if(col_x!=col_y) a[col_x]=col_y; } int ans=0; for(int i=1;i<=n;i++) if(a[i]==i) ans++; cout<<ans<<endl; } return 0; }
T3 山峰
搞什么啊,模拟赛就这样考一道小搜索真的好吗?
一个高度为h地点被称作d-山峰,只有满足从这里出发,在不经过小于等于h-d的地点的前提下无法达到比它更高的地方。
简洁易懂的语言加上500的数据范围,我仿佛在做普及组QAQ
所以这题就是个时间tag优化bfs。
具体细节看代码吧 ?
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> using namespace std; int dx[5]={0,0,1,0,-1}; int dy[5]={0,1,0,-1,0}; int n,m,d,tim,maxn; int mp[507][507],vis[507][507]; bool flag; struct node{ int x,y; }; void bfs(int x,int y) { queue<node> q; q.push((node){x,y}); int high=mp[x][y]-d; vis[x][y]=++tim; while(!q.empty()) { node nw=q.front(); q.pop(); for(int i=1;i<=4;i++) { int nwx=nw.x+dx[i]; int nwy=nw.y+dy[i]; if(nwx<1||nwx>n||nwy<1||nwy>m) continue; if(mp[nwx][nwy]<=high||vis[nwx][nwy]==tim) continue; if(mp[nwx][nwy]>mp[x][y]) { flag=1; return; } vis[nwx][nwy]=tim; q.push((node){nwx,nwy}); } } return; } int main() { scanf("%d%d%d",&n,&m,&d); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&mp[i][j]); maxn=max(maxn,mp[i][j]); } } int ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(mp[i][j]==maxn) continue; bfs(i,j); if(flag) { ans++; flag=0; } } } cout<<n*m-ans<<endl; return 0; }
总结
最后总结一下,其实B组的题还是蛮水的QAQ
期待下次可以200+