1. 程式人生 > 其它 >Codeforces Round #621 (Div. 1 + Div. 2)

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

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