比赛链接:https://ac.nowcoder.com/acm/contest/5026
D 最短路变短了
这题当时没想到,后来看了别人写的题解恍然大悟。解题思路就是如果一条边反向之后最短路变小了,肯定是用了这个反向边。如果用了这条边(假设这条边反向后的起点为 i,终点为 j,长度为 vij ),那么只有当 dis1-n > dis1-i + vij + disj-n 才能比反向前最短路距离小。先看 > 的左边,既然要和反向前最短路比较,那么肯定要把反向前最短路求出来。用 dijkstra 求出 1-n 的最短路后,我们再看 > 的右边。dis1-i 在我们求 1-n 最短路时已经求出来了,vij也是已知的,只有 disj-n还没有,所以现在只有一个问题,如何求出每个点的 disj-n?
这里可以用反向建图实现,既然正向建图能求 1-n 的最短路能求出各点的 dis1-i,那么反向建图求 n-1的最短路就能求出各点的 disn-j ,这和正向建图的各点 disj-n 是一样的。
这样我们就求出了所有需要的条件,然后这题就AC啦。
代码如下
#include <iostream>
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn=2e5+5;
const int maxm=4e5+5;
const long long inf=2e18+5;
struct node
{
int from,to,next,value;
}p[maxm];
struct Node
{
int nd;
long long len;
friend bool operator < (Node a,Node b)
{
return a.len > b.len;
}
};
long long dis[maxn];
int head[maxn];
int cnt,n,m,q;
void add(int x,int y,int v)
{
p[++cnt].to=y;
p[cnt].from=x;
p[cnt].next=head[x];
p[cnt].value=v;
head[x]=cnt;
}
void dijkstra(int beg)
{
priority_queue<Node>q;
q.push({beg,0});
dis[beg]=0;
while(!q.empty())
{
Node tmp=q.top();
q.pop();
int u=tmp.nd;
long long k=tmp.len;
for(int i=head[u];i;i=p[i].next)
{
int v=p[i].to;
int w=p[i].value;
if(dis[v]>k+w)
{
dis[v]=k+w;
q.push({v,dis[v]});
}
}
}
}
int main()
{
for(int i=0;i<maxn;i++)
dis[i]=inf;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,v;
scanf("%d %d %d",&x,&y,&v);
add(x,y,v);
}
dijkstra(1);
for(int i=1;i<=m;i++)
{
add(p[i].to+n,p[i].from+n,p[i].value);
}
dijkstra(2*n);
/*for(int i=1;i<=2*n;i++)
cout<<dis[i]<<" ";
cout<<endl;
*/
scanf("%d",&q);
while(q--)
{
int u;
scanf("%d",&u);
int f=p[u].from;
int t=p[u].to;
int v=p[u].value;
if(dis[n]>(dis[t]+dis[f+n]+v))
puts("YES");
else
puts("NO");
}
return 0;
}
E 相似的子串
这题要用 二分 + 哈希,首先 x 满足单调性,所以很容易想到二分,那么怎么判断此时的值满不满足条件呢。我们可以从前往后找长度为 x 的字符串,这里明显贪心,因为要满足条件的话自然是越往前越好,这样可以使后面有更多的满足条件。所以我们要从前往后找。通过 hash 值来判断字符串,并记录在 unordered_map(map是O(logn)的查询,unordered_map是O(1)的查询),最后判断如果字符串个数够了就满足,不够就不满足。
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int base=131;
const int maxn=2e5+5;
unordered_map<ull,pair<int,int> > mp;
ull Hash[maxn],Power[maxn];
char str[maxn];
char ch;
int n,k,l,r,mid,ans;
bool check(int x)
{
mp.clear();
for(int i=x;i<=n;i++)
{
ull haxi = Hash[i]-Hash[i-x]*Power[x];
if(i-mp[haxi].first>=x)
{
mp[haxi].first=i;
mp[haxi].second++;
}
if(mp[haxi].second>=k)
return true;
}
return false;
}
int main()
{
cin>>n>>k>>str+1;
Power[0]=1;
for(int i=1;i<=n;i++)
{
Hash[i]=Hash[i-1]*base+(str[i]-'a')+1;
Power[i]=Power[i-1]*base;
}
l=0;
r=n/k+1;
while(l<r)
{
mid=(l+r)>>1;
if(check(mid))
l=mid+1,ans=mid;
else
r=mid;
}
printf("%d\n",ans);
return 0;
}