Codeforces Round #621 (Div. 1 + Div. 2)

Posted on 2022-04-14 14:53  Capterlliar  阅读(26)  评论(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;
}
View Code