2 条题解
-
1
有矩阵乘法我无疑是兴奋的。
并查集家族新增一名猛将。
请先保证这个会了喵:【代码】带权并查集模板-CSDN博客

// by hansang / proMatheus #include<bits/stdc++.h> using namespace std; typedef long long LL; const LL P = 998244353; const int N = 2e5 + 10; struct Matrix { LL a[2][2]; Matrix() { memset(a, 0, sizeof(a)); } } d[N]; Matrix operator*(Matrix na, Matrix nb) { Matrix nc; for (int k = 0; k <= 1;k ++) { for (int i = 0; i <= 1; i ++) { for (int j = 0; j <= 1; j ++) { nc.a[i][j] = (nc.a[i][j] + na.a[i][k] * nb.a[k][j] % P) % P; } } } return nc; } bool operator==(Matrix na, Matrix nb) { for (int i = 0; i <= 1; i ++) { for (int j = 0; j <= 1; j ++) { if (na.a[i][j] != nb.a[i][j]) { return false; } } } return true; } Matrix get_inv(Matrix no) { Matrix ne; ne.a[0][0] = no.a[1][1]; ne.a[0][1] = -no.a[0][1] + P; ne.a[1][0] = -no.a[1][0] + P; ne.a[1][1] = no.a[0][0]; return ne; } int fa[N]; int findfa(int x) { if (fa[x] == x) { return fa[x]; } int to = findfa(fa[x]); d[x] = d[fa[x]] * d[x]; // 从父亲到孩子,从左到右 return fa[x] = to; } int main () { ios::sync_with_stdio(false); cin.tie(0); int n, Q; cin >> n >> Q; for (int i = 0; i < n; i ++) { // 阴没边了 base-0 fa[i] = i; for (int j = 0; j <= 1; j ++) { d[i].a[j][j] = 1; // 单位矩阵 } } while (Q --) { int opt; cin >> opt; int u, v; cin >> u >> v; int fu = findfa(u), fv = findfa(v); if (opt == 0) { Matrix t; for (int i = 0; i <= 1; i ++) { for (int j = 0; j <= 1; j ++) { cin >> t.a[i][j]; } } if (fu != fv) { fa[fv] = fu; d[fv] = d[u] * get_inv(t) * get_inv(d[v]); // 关于矩乘等号移位规则: // a * b = c * d // 右边的移到右边 // a * b * d^{-1} = c // a = c * d * c^{-1} // 左边移到左边 // c^{-1} * a * b = d // b = a^{-1} * c * d // 反正记住乘号两边不能随意换位置就是了 // d[u] = d[v] * t // 这里的 fv 因为还是并查集的头目,所以 d[fv] 是单位矩阵 // 我们通过 d[u] 和 d[v] 的关系重塑 d[fv] // d[fv] = d[u] * t^{-1} * d[v]^{-1} // 从左到右执行: // 第 1 步:应用反向约束,从 u 到 v // 第 2 步:撤销 d[v] 的贡献,从 v 到 v 的根 fv // 为什么是这个顺序? // 因为 d[fv] * d[v] * t = d[fu](这玩意是单位矩阵要不要都行) * d[u] // 你把等式左边的从右到左,按照移位规则移到右边去 cout << "1\n"; } else { if (d[v] * t == d[u]) { cout << "1\n"; } else { cout << "0\n"; } } } else { if (fu != fv) { cout << "-1\n"; } else { // d[u] = d[v] * t // d[v]^{-1} * d[u] = t Matrix t = get_inv(d[v]) * d[u]; for (int i = 0; i <= 1; i ++) { for (int j = 0; j <= 1; j ++) { cout << t.a[i][j] << " "; } } cout << "\n"; } } } return 0; } -
0
#include<bits/stdc++.h> using namespace std; #define int long long #define N 200010 #define mod 998244353 //a b //c d struct node{ int a,b,c,d; }; bool operator==(node n1,node n2){ return n1.a==n2.a &&n1.b==n2.b &&n1.c==n2.c &&n1.d==n2.d; } node operator*(node n1,node n2){ return (node){ (n1.a*n2.a+n1.b*n2.c)%mod, (n1.a*n2.b+n1.b*n2.d)%mod, (n1.c*n2.a+n1.d*n2.c)%mod, (n1.c*n2.b+n1.d*n2.d)%mod }; } node change(node n1){ return {n1.d,-n1.b+mod,-n1.c+mod,n1.a}; } int n,q,fa[N]; node d[N]; int findfa(int x){ if(fa[x]!=x){ int top=findfa(fa[x]); d[x]=d[fa[x]]*d[x]; fa[x]=top; } return fa[x]; } signed main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); cin>>n>>q; for(int i=0;i<n;i++)fa[i]=i,d[i]={1,0,0,1}; while(q--){ int op;cin>>op; if(op==0){ int x,y,A,B,C,D;cin>>x>>y>>A>>B>>C>>D; node a={A,B,C,D}; int tx=findfa(x),ty=findfa(y); if(tx!=ty){ fa[ty]=tx; d[ty]=d[x]*change(a)*change(d[y]); cout<<"1\n"; } else{ if(change(d[y])*d[x]==a)cout<<"1\n"; else cout<<"0\n"; } } else{ int x,y;cin>>x>>y; int tx=findfa(x),ty=findfa(y); if(tx!=ty){ cout<<"-1\n"; } else{ node ans=change(d[y])*d[x]; cout<<ans.a<<' '<<ans.b<<' '<<ans.c<<' '<<ans.d<<'\n'; } } } return 0; }
- 1
信息
- ID
- 8122
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 7
- 标签
- 递交数
- 44
- 已通过
- 9
- 上传者