Codeforces Round #621 (Div. 1 + Div. 2)
Posted on 2022-04-14 14:53 Capterlliar 阅读(27) 评论(0) 编辑 收藏 举报A. Cow and Haybales
题意:有n堆干草,每次可以挑相邻的两个数,一个加一一个减1,求这样搬d次后第一堆干草最多有多少。
解:一开始读假题了,以为要求d次操作后高度为1的干草堆最多有多少。。。直接从左到右把能搬的草搬完就行。
B. Cow and Friend
题意:起点为0,终点为x。给出n个数,每次可以选一个数在二维平面上跳相应长的距离,求最少几次能跳完。
解:令能跳的最大距离为m,m>x时,如果有能直接到终点的距离答案为1,否则两下能跳过去;m=x答案为1;m<x时,按最大距离跳,最后走个三角形,即答案为(d-1)/x+1,减一是为了兼容x为m倍数的情况。
C. Cow and Message
题意:给出一个字符串,挑出它所有下标为等差数列的子串,求出现最多的子串出现了几次。
解:如果出现最多的子串长为3,那么长为2的子串也出现了这么多次。所以最终答案只能由长为1或2的子串带来,暴力枚举计数即可。
D. Cow and Fields
题意:给出一张图和其中顶点的一个子集,可以在子集中选两个点加一条边,求加完这条边后起点1到终点n最短路的最大值。
解:首先加了这条边后最短路不可能边长,那么考虑怎么加能使最短路变短得更少。首先如果原来有这条边,那选它一定是最好的;由此引出了一个错误做法:整张图bfs一遍分层,挑层数相差最小的加边。这个做法竟然跑过了31个点。
但这张图如果选起点和终点就GG了。
所以老实考虑计算式子:选点x和y,新的最短路长度为min(dis[0...x]+1+dis[y...n],dis[0...y]+1+dis[x...n],原最短路长度)。O(n2)显然不行,考虑移项:
dis[0...x]+dis[y...n]<dis[0...y]+dis[x...n]
dis[0...x]-dis[x...n]<dis[0...y]-dis[y...n]
现在一边只有一个未知数,可以考虑按这个差值排序,从而保证答案一定是从前往后选两个点。最终答案要dis[0...x]+dis[y...n]+1,那遍历一遍挑最大的就好了。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define inf 0x7fffffff int n,m,k; int a[maxx]={0}; vector<int> e[maxx]; int vis[maxx]={0}; int dis[maxx][2]; void dijk(int start,int num){ for(int i=1;i<=n;i++) dis[i][num]=inf,vis[i]=0; priority_queue<pair<int,int> > q; dis[start][num]=0; q.push(make_pair(0,start)); while(!q.empty()){ int now=q.top().second; q.pop(); if(vis[now]) continue; vis[now]=1; for(auto to:e[now]){ int f=dis[now][num]+1; if(f<dis[to][num]){ dis[to][num]=f; q.push(make_pair(-dis[to][num],to)); } } } } signed main(){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=k;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); e[x].push_back(y); e[y].push_back(x); } dijk(1,0); dijk(n,1); int ans=0; sort(a+1,a+k+1,[](int x,int y){ return dis[x][0]-dis[x][1]<dis[y][0]-dis[y][1]; }); int maxn=-inf; for(int i=1;i<=k;i++){ ans=max(ans,maxn+dis[a[i]][1]); maxn=max(maxn,dis[a[i]][0]); } printf("%d\n",min(ans+1,dis[n][0])); return 0; }