首页 > 其他分享 >ARC090E 题解

ARC090E 题解

时间:2024-03-07 13:24:20浏览次数:21  
标签:del2 dis1 dis2 int 题解 del1 ARC090E Mod

Solution

一道不错的计数题。因为直接求不相遇的方案十分复杂,所以考虑正难则反,用总的方案数减去相遇的方案数。求方案数很套路:在求最短路的时候开一个数组 \(del\) 记录到达点 \(i\) 的最短路条数,更新最短路时顺便更新即可。

跑完最短路后,设 \(dis1\) 为 \(s\) 到 \(t\) 的最短路数组,\(del1\) 为 \(s\) 到 \(t\) 的最短路的条数的数组,\(dis2\) 和 \(del2\) 同理,易得总的方案数为 \({del_t}^2\),接下来考虑求相遇的方案数,共分为两种情况:

  1. 在点上相遇。设 \(i\) 为相遇点,那么有 \(dis1_i=dis2_i\),且 \(dis1_i+dis2_i=dis1_t\),方案数为 \({del1_i}^2 \times {del2_i}^2\)。

  2. 在边上相遇,设在 \(i\) 边上相遇,且连接 \(u\),\(v\),边权为 \(w\),那么有 \(dis1_u+dis2_v+w=dis1_t\),且 \(dis1_u+w>dis2_v\),以及 \(dis2_v+w>dis1_u\),方案数为 \({del1_i}^2 \times {del2_i}^2\)。

最后输出答案。注意取模。

// Celestial Cyan 
// Luogu uid : 706523 
// Luogu : https://www.luogu.com.cn/problem/AT_arc090_c
// CF : 
// AT : https://www.luogu.com.cn/remoteJudgeRedirect/atcoder/arc090_c
// FTOJ : 
// Contest : AtCoder Regular Contest 090
// Cnblogs : 
// Memory Limit: 256 MB
// Time Limit: 2000 ms 
// 2023/8/1    

#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
#define il inline 
#define db double
#define low(x) x&-x
#define ls(x) x<<1
#define rs(x) x<<1|1 
#define pb(x) push_back(x)
#define gcd(x,y) __gcd(x,y) 
#define lcm(x,y) x*y/gcd(x,y) 
#define debug() puts("-------")  
using namespace std;
typedef pair<int,int> pii;
typedef pair<int,pii> PII; 
const int N=1e5+10,M=2e5+10,Mod=1e9+7,INF=1e9+7; 
int n,m; 
int s,t; 
int h[N],idx=0; 
bool st1[N],st2[N];
int u[N],v[N],w[N];
int dis1[N],dis2[N]; 
int del1[N],del2[N]; 
struct Node{ 
	int w; 
	int to,ne; 
}tr[M<<1]; 
struct Mind{ 
	il bool operator<(Mind &Cyan)const{ } 
}; 
il int read(){ 
	int x=0,f=1; char c=getchar();
	while(c<'0'||c>'9'){ if(c=='-') f=-1; c=getchar(); }
	while(c>='0'&&c<='9'){ x=(x<<3)+(x<<1)+c-48; c=getchar(); }
	return x*f;
} 
il void add(int u,int v,int w){ 
	tr[idx].w=w,tr[idx].to=v,tr[idx].ne=h[u],h[u]=idx++; 
} 
il void dij1(){
	priority_queue<pii> q; q.push({0,s});
	memset(st1,false,sizeof st1);  
	for(int i=1;i<=n;i++) dis1[i]=INF; dis1[s]=0; del1[s]=1; 
	while(!q.empty()){ 
		int u=q.top().y; q.pop();
		if(st1[u]) continue; st1[u]=true; 
		for(int i=h[u];i!=-1;i=tr[i].ne){
			int to=tr[i].to; 
			if(dis1[to]>dis1[u]+tr[i].w){
				dis1[to]=dis1[u]+tr[i].w; 
				del1[to]=del1[u]; q.push({-dis1[to],to}); 
			} else if(dis1[to]==dis1[u]+tr[i].w) del1[to]=(del1[to]+del1[u])%Mod; 
		} 
	}
} 
il void dij2(){
	priority_queue<pii> q; q.push({0,t}); 
	memset(st2,false,sizeof st2); 
	for(int i=1;i<=n;i++) dis2[i]=INF; dis2[t]=0; del2[t]=1;  
	while(!q.empty()){ 
		int u=q.top().y; q.pop();
		if(st2[u]) continue; st2[u]=true; 
		for(int i=h[u];i!=-1;i=tr[i].ne){ 
			int to=tr[i].to; 
			if(dis2[to]>dis2[u]+tr[i].w){
				dis2[to]=dis2[u]+tr[i].w; 
				del2[to]=del2[u]; q.push({-dis2[to],to}); 
			} else if(dis2[to]==dis2[u]+tr[i].w) del2[to]=(del2[to]+del2[u])%Mod; 
		} 
	}
} 
signed main(){ 
	memset(h,-1,sizeof h); 
	n=read(),m=read(); s=read(),t=read(); 
	for(int i=1;i<=m;i++){ 
		u[i]=read(),v[i]=read(),w[i]=read(); 
		add(u[i],v[i],w[i]),add(v[i],u[i],w[i]);  
	} dij1(); dij2(); int ans=del1[t]*del1[t]%Mod; // cout<<ans<<endl; 
	for(int i=1;i<=n;i++){ 
		if(dis1[i]+dis2[i]==dis1[t]&&dis1[i]==dis2[i]){
			ans=(ans-del1[i]*del1[i]%Mod*del2[i]%Mod*del2[i]%Mod)%Mod;  
		} 
	} for(int i=1;i<=m;i++){ 
		if(dis1[u[i]]+dis2[v[i]]+w[i]==dis1[t]&&dis1[u[i]]+w[i]>dis2[v[i]]&&dis2[v[i]]+w[i]>dis1[u[i]]){
			ans=(ans-del1[u[i]]*del1[u[i]]%Mod*del2[v[i]]%Mod*del2[v[i]]%Mod)%Mod; 
		} swap(u[i],v[i]); 
		if(dis1[u[i]]+dis2[v[i]]+w[i]==dis1[t]&&dis1[u[i]]+w[i]>dis2[v[i]]&&dis2[v[i]]+w[i]>dis1[u[i]]){
			ans=(ans-del1[u[i]]*del1[u[i]]%Mod*del2[v[i]]%Mod*del2[v[i]]%Mod)%Mod; 
		} 
	} printf("%lld\n",(ans%Mod+Mod)%Mod);  
	return 0;
} /* */ 

标签:del2,dis1,dis2,int,题解,del1,ARC090E,Mod
From: https://www.cnblogs.com/Celestial-cyan/p/18058679

相关文章

  • AT_abc256_h [ABC256Ex] I like Query Problem 题解
    分析用势能线段树。对于一段数字\(a_l\)到\(a_r\),每次全部除以一个大于\(1\)的数,不难发现最多除以\(\logx\)次就会使\(a_l\)到\(a_r\)全部变成\(0\),其中\(x\)是区间最大值。所以,在没有操作\(2\)的情况下,我们可以在每次操作\(1\)的时候都单点修改,只要在某个......
  • CF1070C Cloud Computing 题解
    分析思路不难想,我们对于第\(i\)个计划的时间,可以分成\(l\)和\(r+1\)两部分。用权值线段树维护,在第\(l\)天的时候就将该计划的内容加入权值线段树中,直到过了该计划的时间,也就是第\(r+1\)天,再将这个计划的内容删除。把每一天需要修改的内容存进vector中,修改完查询权值......
  • AT_dwacon5th_prelims_c k-DMC 题解
    分析先考虑\(k=n\)的情况。对于\(s_j=M\)的时候,其能够匹配的\(s_i=D\)的数量很显然是\(i\lej-1\)的时候的数量,求前缀和就能得到。而对于\(s_j=C\)的时候,能够完整匹配的就是\(i\lej-1\)的时候所有\(s_i=M\)能够匹配的数量之和,再套个前缀和就行了。复杂度是\(O......
  • CF1899G Unusual Entertainment 题解
    分析一眼树上启发式合并。定义\(x_i\)为节点\(i\)在序列\(p\)中的下标。则问题转化为:对于每组\(l,r,k\),询问以\(k\)为根的子树中是否有一个以上的节点,满足\(l\lex_j\ler\)。使用set存以\(i\)为根的子树中\(x_j\)的有序排列。则对于每个\(k=i\)的询问,去合......
  • AT_abc328_f [ABC328F] Good Set Query 题解
    分析考虑并查集。对于\(a_i,b_i,d_i\),若\(a_i,b_i\)在之前的满足要求的操作中,\(a_i,b_i\)不在同一个集合里,则在之前\(X_{a_i},X_{b_i}\)的相对差值是可以任意改变的。令\(k=X_{a_i}-X_{b_i}\),则我们需要将\(a_i\)所在集合中所有元素的值增加\(d_i-k\)。然后将\(a_i,b......
  • CF1895D XOR Construction 题解
    分析对于异或,有性质\(a\oplusb=c,a\oplusc=b,a\oplusa=0\)。则对于\(a_i\oplusa_{i+1}\),其表示的结果就是\(b_{i}\oplusb_{i+2}\)。做一个前缀异或和,就能够得到\(b_1\)与\(b_2,b_3,\dots,b_n\)的异或结果。考虑枚举\(b_1\),因为在有解的情况下\(b_1\op......
  • CF1896D 题解
    Solution令\(l,r\)能使\(\sum\limits_{i=l}^{r}a_i=S\)。考虑先令\(l=1\),那么如果存在\(\sum\limits_{i=1}^{r}=S\),即输出YES。如果没有,则一定有\(\sum\limits_{i=1}^{r}=S-1\),且\(a_{r+1}=2\)。考虑对\(l,r\)进行调整:将\(l\)向左移,\(r\)向右移。可以发现当\(......
  • AT_abc222_f [ABC222F] Expensive Expense 题解
    分析没脑子的题目。一眼换根DP。定义\(\mathit{f}_{i}\)表示\(i\)到\(i\)为根子树中某一个节点的距离最大值;\(\mathit{g}_{i}\)表示\(i\)经过其父节点到某个节点的距离最大值。那答案就是\(\max(\mathit{f}_i,\mathit{g}_i)\)。考虑转移。\(\mathit{f}_i\)的转移很......
  • CF1223F Stack Exterminable Arrays 题解
    分析接着这个说。现在我们需要优化\(\mathit{nxt}_{i}\)。重新定义一下,\(\mathit{nxt}_{i,j}\)表示在后\(i\)个数中,\(j\)第一次出现的位置,且\([i+1,\mathit{nxt}_{i+1,a_i}-1]\)是一个合法串。这玩意很像一个DP,所以完全可以按照DP的转移思路转移:\(\mathit{nxt}_{i,j}=......
  • CF514D R2D2 and Droid Army 题解
    分析乱搞题。考虑将区间\([l,r]\)中所有人干掉的代价。设\(cnt_{i}=\max\limits_{j=l}^{r}a_{j,i}\),则代价为:\(\sum\limits_{i=1}^{m}cnt_i\)。很显然,只有在\(\sum\limits_{i=1}^{m}cnt_i\lek\)是,我们才能将这些人全部干掉。考虑枚举右端点\(r\),与每个\(r\)对应的最......