第 132 场周赛——质数小结论,并查集配Floyd

https://www.acwing.com/activity/content/competition/problem_list/3648/

B题收获:

1.利用题目告诉的结论:1e9范围质数之差小于300
2.一个数不被2-a的任何数整除 等价于他的最小质因子需要大于a

c题:初步宏观思路:不难想到用并查集维护类别,只需将每一个类缩成一个点,由于最多只有500个类别,跑一个floyd就可以了

部分细节处理:我的思路是类别用并查集维护,开了一个哈希表去存每个类别对应的根节点是最终floyd的第几个点,in fact,这样做复杂了。一会说正解,然后我在读入边的时候去判断,如果两个不是同一类,我们需要建图存边。
如果是同一类,我们只要0边,因为题目要求内部距离为0。在check的时候,本质上是看看联通性,因为我们又弄了一个并查集去看联通性,但是只合并了内部0的边,最后看看每个类别的size是不是和原先dsu=相同。
就这样交了一发,然后wa了,发现内部的两个点可以通过外部实现联通(分组:1和2,3。。。1与3联通,2与3联通,那么1和2联通,上面的做法被hack。
所以我们必须考虑合并所有为0的边,最后check的时候是对所有点看看相邻的点,如果是同一类却在维护联通性并查集中不同root,直接retur no。

#include <bits/stdc++.h> using namespace std; #define ll long long //# define int long long #define ull unsigned long long #define pii pair<int,int> #define double long double #define baoliu(x, y) cout << fixed << setprecision(y) << x #define endl "\n" const int N = 2e5 + 10; const int M = 1e6 + 10; const int inf = 0x3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; int n, m; int a[N]; int d[502][502]; int k;//k类 unordered_map<int,int>mp;//按类别缩点以后的根对应的编号 int cnt=0;//记录当前是第几个类 void floyd(){ for(int v=1;v<=k;v++){ for(int i=1;i<=k;i++){ for(int j=1;j<=k;j++){ d[i][j]=min(d[i][v]+d[v][j],d[i][j]); } } } } struct DSU { vector<int> f, siz; DSU() {} DSU(int n) { init(n); } void init(int n) { f.resize(n); std::iota(f.begin(), f.end(), 0); siz.assign(n, 1); } int find(int x) { while (x != f[x]) { x = f[x] = f[f[x]]; } return x; } bool same(int x, int y) { return find(x) == find(y); } bool merge(int x, int y) { x = find(x); y = find(y); if (x == y) { return false; } siz[x] += siz[y]; f[y] = x; return true; } int size(int x) { return siz[find(x)]; } }; void solve(){ cin>>n; DSU dsu(n+1);DSU fn(n+1); cin>>m; cin>>k; int val=1; for(int i=1;i<=k;i++){ mp[val]=++cnt; int c; cin>>c; for(int j=val;j<=val+c-1;j++){ dsu.merge(val,j); } val=val+c; } for (int i = 1; i <= k; i ++ ) for (int j = 1; j <= k; j ++ ) if (i == j) d[i][j] = 0; else d[i][j] = inf; while(m--){ int u,v,w; cin>>u>>v>>w; int r1=dsu.find(u),r2=dsu.find(v); if(r1==r2){ if(w)continue; else { fn.merge(u,v); } } else { if(w==0)fn.merge(u,v); int ve1=mp[r1],ve2=mp[r2]; d[ve2][ve1]=d[ve1][ve2]=min(d[ve1][ve2],w); } } //bool flag=true; for(int i=2;i<=n;i++){ int s1=dsu.find(i-1),s2=dsu.find(i);//类别 int r1=fn.find(i-1),r2=fn.find(i);//仅通过0边看是不是联通 if(s1==s2&&r1!=r2){ cout<<"No"<<endl;; return ; } } cout<<"Yes"<<endl; floyd(); for(int i=1;i<=k;i++){ for(int j=1;j<=k;j++){ if(d[i][j]==inf)cout<<-1<<" "; else cout<<d[i][j]<<" "; } cout<<endl; } } int main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(false); int t; t=1; while (t--) { solve(); } return 0; }

正解:我们只需要用一个id数组存下每个点对应的类别,在维护连通性的时候使用并查集,最后check的时候我们只需要保证两个同类别的点属于同一个根至于这个根是不是原来这个类在这个问题中我们并不关心,因为我们只关心连通性。

#include <cstring> #include <iostream> using namespace std; const int N = 1e5 + 10, M = 510, INF = 0x3f3f3f3f; int n, m, k; int id[N]; int p[N]; int dist[M][M]; int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } bool verify() { for (int i = 2; i <= n; i++) if (id[i - 1] == id[i] && find(i - 1) != find(i)) return false; return true; } void floyd() { for (int u = 0; u < k; u++) for (int i = 0; i < k; i++) for (int j = 0; j < k; j++) dist[i][j] = min(dist[i][j], dist[i][u] + dist[u][j]); } int main() { scanf("%d%d%d", &n, &m, &k); for (int i = 0, j = 1; i < k; i++) { int cnt; scanf("%d", &cnt); while (cnt--) id[j++] = i; } memset(dist, 0x3f, sizeof dist); for (int i = 0; i < k; i++) dist[i][i] = 0; for (int i = 1; i <= n; i++) p[i] = i; for (int i = 0; i < m; i++) { int a, b, w; scanf("%d%d%d", &a, &b, &w); if (!w && find(a) != find(b)) p[find(a)] = find(b); int u = id[a], v = id[b]; dist[u][v] = dist[v][u] = min(dist[u][v], w); } if (verify()) { puts("Yes"); floyd(); for (int i = 0; i < k; i++) { for (int j = 0; j < k; j++) { if (dist[i][j] == INF) dist[i][j] = -1; printf("%d ", dist[i][j]); } puts(""); } } else { puts("No"); } return 0; }

__EOF__

本文作者爱飞鱼
本文链接https://www.cnblogs.com/mathiter/p/17873749.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   potential-star  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示