A. Cow and Haybales
题意:有n堆干草,每次可以挑相邻的两个数,一个加一一个减1,求这样搬d次后第一堆干草最多有多少。
解:一开始读假题了,以为要求d次操作后高度为1的干草堆最多有多少。。。直接从左到右把能搬的草搬完就行。
B. Cow and Friend
题意:起点为0,终点为x。给出n个数,每次可以选一个数在二维平面上跳相应长的距离,求最少几次能跳完。
解:令能跳的最大距离为m,m>x时,如果有能直接到终点的距离答案为1,否则两下能跳过去;m=x答案为1;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...x]-dis[x...n]
现在一边只有一个未知数,可以考虑按这个差值排序,从而保证答案一定是从前往后选两个点。最终答案要dis[0...x]+dis[y...n]+1,那遍历一遍挑最大的就好了。
代码:
#include
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_queueint,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]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;
}