给定一张
,求其中有多少秘密基地
。定义一个所谓的秘密基地
,就是距离
号点的
恰好等于
的位置,这个位置可以在一个结点上,也可以在一条边的中间。
点数 满足 ,边数 满足 ,对于任意一条边,边权 满足 。
最短路径,想到了什么?对,单源最短路算法!!!因为边权非负,所以我们可以用dijkstra
算法。
求出最短路后,对于点,我们可以直接判断它是否为秘密基地
。但是,对于边,我们的判断比较复杂,具体地,就是:
- 从 到边的起点的长度必须 。
- 从边的起点到
秘密基地
的距离 边的长度的 (为了避免重复)
但是,这样虽然没有重复,但有遗漏,即正好在边的
的位置的秘密基地
我们没有统计,为此,我们要特别判断每条边的一半那个位置。
#define ll long long
const int N=1e5+100;
struct edge{
int next,u,to,len;
}e[N<<1];int h[N],tot;
inline void add(int a,int b,int c){
e[++tot]=(edge){h[a],a,b,c};h[a]=tot;
e[++tot]=(edge){h[b],b,a,c};h[b]=tot;
}
priority_queue<pair<ll,int> >q;
ll dis[N];bool vis[N];int n;
const ll inf=1000000000000000ll;
void dijkstra(int s){
for(int i=1;i<=n;i++){
vis[i]=true;dis[i]=inf;
}
dis[s]=0;q.push(make_pair(0,s));
while (q.size()){
pair<int,int> f=q.top();q.pop();
register int u=f.second;
if (!vis[u]) continue;
vis[u]=false;//Remember!!!
for(int i=h[u];i;i=e[i].next){
register int to=e[i].to;
if (dis[to]>dis[u]+e[i].len){
dis[to]=dis[u]+e[i].len;
q.push(make_pair(-dis[to],to));
}
}
}
}
int m,ans,start,cnt;ll L;
int main(){
freopen("t1.in","r",stdin);
n=read();m=read();start=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
add(u,v,read());
}
dijkstra(start);L=read();
for(int i=1;i<=n;i++)
if (dis[i]==L) ans++;
for(int i=1;i<=tot;i+=2){
register int u=e[i].u,v=e[i].to,w=e[i].len;
if (dis[u]<L&&dis[u]+w>L&&w-(L-dis[v])>L-dis[u]) cnt++;
if (dis[v]<L&&dis[v]+w>L&&w-(L-dis[u])>L-dis[v]) cnt++;
if (dis[u]<L&&dis[v]<L&&dis[u]+dis[v]+w==(L<<1)) cnt++;
}
printf("%d",ans+cnt);
return 0;
}
瓦斯亚
有两个数字:
和
。然而,瓦斯亚
发现数字
太短了 (???)。所以他决定重复这个操作,把
延长
次。
一个数字的加长操作意味着在右边的数字上恰好加上一个数字(十进制),前提是延长后得到的数字可以被Vasya
的数字
整除。如果无法得到能被
整除的数,则不能进行延长操作。
你的任务是帮助瓦西娅
,并输出最后得到的数字得到的数字。如果不能操作,输出-1
。
第一行包含三个整数:
这是一道考语文的题目,重点在读清楚题目。
这句话是什么意思?就是
操作后都要判断是否可以被
整除,如果不能,则撤销这一步操作,要么输出
表示无法操作,要么重新进行操作。
那么,解读清楚题目后,算法就很清楚,很简单了,先枚举在 的末尾加一个什么数字( 到 间的数码),看看是否为 的倍数,如果是,重复在新数字的末尾加 即可。
讲的很笼统(因为我的表述可能不是很好),具体看代码。