JYOI 四月普及模拟赛 题解
这场比赛是本蒟蒻出的。
第一次出比赛,给原来四中校内的同学做一做,当然很多题不是原创的是搬的,毕竟水平有限
当然整场比赛还是比较简单的,毕竟难度只到普及,不知道大家自我感觉如何,如果对比赛有什么建议也可以在评论区留言
题解如下:
T1 方块游戏(game)
改编自[NOI2002] 银河英雄传说
一道水题 说实话挺简单的不知道为啥洛谷是蓝题,我觉得就普及+难度
数据范围很大,暴力模拟显然是不能直接做出来的我们考虑并查集优化
这道题实质不就是一道带权并查集对于每个点,分别记录所属链的头结点、该点到头结点的距离以及它所在集合的大小。
每次合并将y接在x的尾部,改变y头的权值和所属链的头结点,同时改变x的尾节点。
注意:每次查找的时候也要维护每个节点的权值。(很重要
每次查询时计算两点的权值差。标程放在下面,这应该很详细了,看下一题吧
#include <iostream> #include <cstring> #include <algorithm> #define For(i,m,n) for(int i=m;i<=n;i++) #define sc scanf #define pr printf const int N = 1e5 + 10; using namespace std; int n,m,k,t,p[N],ret[N],cnt[N]; char op[2]; int find(int x) { if(x == p[x])return x; int y = p[x]; p[x] = find(p[x]); ret[x] += ret[y]; return p[x]; } int main() { freopen("game.in", "r", stdin); freopen("game.out", "w", stdout); sc("%d",&n); For(i,1,n)p[i] = i,cnt[i] = 1; For(i,1,n) { int j; sc("%s%d",op,&j); if(op[0] == 'M') { sc("%d",&k); int x = find(j),y = find(k); p[x] = y; ret[x] += cnt[y]; cnt[y] += cnt[x]; } else { find(j); pr("%d\n",ret[j]); } } return 0; }
T2 城市联盟(city)
原题来自一本通题目友好城市
题目有两个条件:1.每个城市只能开辟一个高速 2.所有的铁路之间不能相交、
求最多可以建多少条铁路
先讲O(N2)的做法
我们可以这样想,只固定考虑一个阵营的坐标
容易发现 我们要想让铁路不相交,就必须让一个阵营的所有城市排序后,求出另外一边的LCS(最长上升子序列),可以用反证法
然后O(N log N)的做法 就是基于二分对LCS进行优化,优化为一个log;
只不过我数据范围应该大一点——这题才5000,真的是良心,N2都可以过,不想说啥了;
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 5010; typedef pair<int,int> PII; int f[N],q[N]; PII a[N]; int main() { freopen("city.in","r",stdin); freopen("city.out","w",stdout); int n; cin >> n; for(int i = 0; i < n; ++ i) scanf("%d%d",&a[i].first,&a[i].second); sort(a,a + n); int len = 0; q[0] = 10; for(int i = 0; i < n; ++ i) { int l = 0,r = len; while(l < r) { int mid = l + r + 1 >> 1; if(q[mid] < a[i].second) l = mid; else r = mid - 1; } q[r + 1] = a[i].second; len = max(len,r + 1); } cout << len << endl; return 0; }//二分优化LCS
T3 苍穹之路(sky)
这题我稍微改了下题面
翻译一下就是:
给定一个无向图,有n个顶点,m条边,每条边有一个权值t,但当当前走过的边数大于等于了这条路的分值h,这条路就不能再走了。
求顶点s到终点z所走的最小权值和,若走不到,则输出impossible!
这道题一看就是个最短路,多了关键字罢了
标程(伪):
#include <iostream> #include <algorithm> #include <cstring> #include <queue> #define maxn 3000010 //#define int long long #define INF 0x3f3f3f3f using namespace std; bool vis[maxn]; int n,m,s,t,tot,ans,now; int Step[maxn],Dis[maxn],h[maxn]; struct node{int pos,Step,Dis;}; struct edge{int fr,to,dis,cost,nxt;}e[maxn]; inline int read(){ int s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar(); return s*w; } void add(int fr,int to,int dis,int cost){ e[++tot].to=to;e[tot].cost=cost; e[tot].dis=dis;e[tot].nxt=h[fr]; h[fr]=tot; } void spfa(int st){ memset(Dis,INF,sizeof Dis); Dis[st]=Step[st]=0;queue<node> d;//vis[st]=1; d.push((node){st,0,0}); while(!d.empty()){ node u=d.front();d.pop();//vis[u.pos]=0; for(int i=h[u.pos];i != -1;i=e[i].nxt){ if(u.Step>=e[i].cost) continue;int to=e[i].to; if(Dis[to]>u.Dis+e[i].dis||Step[to]>u.Step+1){ Dis[to]=u.Dis+e[i].dis,Step[to]=u.Step+1; d.push((node){to,Step[to],Dis[to]}); } } } } signed main(){ freopen("sky.in","r",stdin); freopen("sky.out","w",stdout); memset(h,-1,sizeof h); scanf("%d%d%d%d",&n,&m,&s,&t); for(int i=1,fr,to,dis,cost;i<=m;i++){ scanf("%d%d%d%d",&fr,&to,&dis,&cost); add(fr,to,dis,cost);add(to,fr,dis,cost); } spfa(s); if(Dis[t]==INF) printf("bao 0\n"); else printf("%d\n",Dis[t]); return 0; }
一场考察较容易基础算法的比赛就这样end
THANKS