我是靠谱客的博主 无奈钢笔,这篇文章主要介绍2019 百度之星初赛三 补题,现在分享给大家,希望可以做个参考。

B.hdu6714 最短路2(最短路/dijkstra+floyd理解)

题目

在Floyd中,记dis[i][j]中最后一次松弛i到j的最短路的点的编号为x,且令d[i][j]=x

sum_{i=1}^{n}sum_{j=1}^{n}d[i][j],n<=1e3,m<=2e3

思路来源

https://blog.csdn.net/a1097304791/article/details/100067541

题解

对每个点暴力dijkstra,把复杂度从O(n^3)降到O(n^2logm)

注意当i到j之间的最短路,只有一条边的时候,d[i][j]为0

所以,d[i][j]中间,应该不考虑等于i或等于j的节点

多条最短路的时候,记录更新节点号最小的那条

代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; typedef long long ll; const int mod=998244353; const int N=1e3+10; const int M=2e3+10; int t,n,m,u,v,w; int head[N],ans[N],cnt; bool vis[N]; ll dis[N],res; struct edge{int to,nex;ll w;}e[M*2]; struct node { ll w; int v; node(ll a,int c):w(a),v(c){ } }; bool operator>(node a,node b) { return a.w>b.w; } priority_queue<node,vector<node>,greater<node> >q; void init() { cnt=0; memset(head,0,sizeof head); } void add(int u,int v,ll w) { e[++cnt].to=v; e[cnt].w=w; e[cnt].nex=head[u]; head[u]=cnt; } void dijkstra(int s) { memset(vis,0,sizeof vis); memset(ans,0,sizeof ans); for(int i=1;i<=n;++i) dis[i]=1e18; q.push(node(0,s));//说明从哪条边转移到这点的 dis[s]=0; while(!q.empty()) { node tmp=q.top(); q.pop(); int v=tmp.v; if(vis[v])continue; vis[v]=1; for(int i=head[v];i;i=e[i].nex) { int to=e[i].to; ll w=e[i].w; if(dis[to]>dis[v]+w) { dis[to]=dis[v]+w; if(v!=s)ans[to]=max(ans[v],v); q.push(node(dis[to],to)); } else if(dis[to]==dis[v]+w) { if(v!=s)ans[to]=min(ans[to],max(ans[v],v)); } } } } int main() { scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); init(); res=0; while(m--) { scanf("%d%d%d",&u,&v,&w); add(u,v,w);add(v,u,w); } for(int i=1;i<=n;++i) { dijkstra(i); for(int j=1;j<=n;++j) res+=ans[j]; } printf("%lldn",res%mod); } return 0; }

C.hdu6715 算术(莫比乌斯反演)

题目

思路来源

https://www.cnblogs.com/cmyg/p/11405524.html

题解

寒假做过gcd的,暑假换成lcm就不会了……

现在觉得,推mobius的式子好有意思!

会了几个公式,很多时候,lcm要根据mu(k)不等于0,提一个mu(k)平方=1出来

 

mu(x*y)=mu(x)*mu(y)*[gcd(x,y)==1]

[gcd(i,j,k)==1]=[gcd(i,j)==1]*[gcd(i,k)==1]*[gcd(j,k)==1]

[gcd(i,k)==1]*[gcd(j,k)==1]*mu(i)*mu(j) \=[gcd(i,k)==1]*[gcd(j,k)==1]*mu(i)*mu(j)*(mu(k))^{2} \=mu(i*k)*mu(j*k)

 

复杂度O(nlogn)

代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e6+10; bool ok[maxn]; int prime[maxn],mu[maxn],cnt; int T,n,m,mn; ll sum[maxn],ans,ans1,ans2,ans3; void sieve() { mu[1]=1; for(ll i=2;i<maxn;++i) { if(!ok[i]) { prime[cnt++]=i; mu[i]=-1; } for(int j=0;j<cnt;++j) { if(i*prime[j]>=maxn)break; ok[i*prime[j]]=1; if(i%prime[j]==0) { mu[i*prime[j]]=0;//如果开的是全局,就不用管 break; } else mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<maxn;++i)//d { for(int j=i;j<maxn;j+=i)//d*k sum[j]+=mu[i]*mu[j/i]; } } int main() { sieve(); scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); mn=min(n,m); ans=0; for(int i=1;i<=mn;++i) { ans1=sum[i]; ans2=0; for(int j=i;j<=n;j+=i) ans2+=mu[j]; ans3=0; for(int j=i;j<=m;j+=i) ans3+=mu[j]; ans+=ans1*ans2*ans3; } printf("%lldn",ans); } return 0; }

 

最后

以上就是无奈钢笔最近收集整理的关于2019 百度之星初赛三 补题的全部内容,更多相关2019内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(93)

评论列表共有 0 条评论

立即
投稿
返回
顶部