CF60C Mushroom Strife 解题报告
1 题目链接
2 题目大意
题目 : 蘑菇冲突
题目大意 :
给定一个
n
n
n个点
m
m
m条边的无向图 (怎么又是图论),每个点上对应一个数值,每条边记录着该边所连接的两个节点对应数值的
L
c
m
Lcm
Lcm(最小公倍数)与
G
C
D
GCD
GCD(最大公因数)。问能否给出一种构造使得该图合法。若能,输出YES
并给出其中一种构造;若不能,输出NO
。
3 解法分析
看到题目的第一眼又是并查集 (我恨数据结构)。
仔细想想发现写了并查集反而不好做,搜索真香。
众所周知,
a
×
b
=
g
c
d
(
a
,
b
)
×
l
c
m
(
a
,
b
)
a\times b=gcd(a,b)\times lcm(a,b)
a×b=gcd(a,b)×lcm(a,b)即,
a
=
g
c
d
(
a
,
b
)
×
l
c
m
(
a
,
b
)
b
a=\frac{gcd(a,b)\times lcm(a,b)}{b}
a=bgcd(a,b)×lcm(a,b)所以我们只要知道其中一个点的数值,就可以求出与之对应的另一个。因此,我们只要枚举每个连通分量中的一个数就可以推出其中所有的数以及他是否合法。枚举的方法也很显然,
d
f
s
dfs
dfs即可。
4 AC Code
Dalao代码 #001
// From KrK
// Rating 2787
#include <iostream>
#include <vector>
using namespace std;
const int Maxn = 101;
const int Inf = 1000001;
int n, m, num[Maxn];
vector <int> neigh[Maxn], g[Maxn], l[Maxn];
bool del[Maxn], taken[Maxn], stop;
int gcd(int x, int y)
{
while (x != 0) {
int tmp = y % x;
y = x;
x = tmp;
}
return y;
}
void Search(int v)
{
int i;
for (i = 0; i < neigh[v].size() && !stop; i++)
if (num[v] % g[v][i] || l[v][i] % num[v]) stop = true;
else {
int newnum = l[v][i] / num[v] * g[v][i];
if (gcd(newnum, num[v]) != g[v][i] ||
num[neigh[v][i]] && num[neigh[v][i]] != newnum) stop = true;
else if (num[neigh[v][i]]) continue;
else {
num[neigh[v][i]] = newnum;
Search(neigh[v][i]);
}
}
}
void DFS(int v)
{
if (del[v]) return;
del[v] = true;
for (int i = 0; i < neigh[v].size(); i++)
DFS(neigh[v][i]);
}
void SwitchBack(int v)
{
if (num[v] == 0) return;
num[v] = 0;
for (int i = 0; i < neigh[v].size(); i++)
SwitchBack(neigh[v][i]);
}
int main()
{
int a, b, c, d;
cin >> n >> m;
for (int i = 0; i < m; i++) {
cin >> a >> b >> c >> d;
neigh[a].push_back(b); g[a].push_back(c); l[a].push_back(d);
neigh[b].push_back(a); g[b].push_back(c); l[b].push_back(d);
}
int i;
for (i = 1; i <= n; i++) if (!del[i]) {
int j;
for (j = 1; j < Inf; j++) {
stop = false;
num[i] = j;
Search(i);
if (!stop) break;
SwitchBack(i);
}
if (j == Inf) break;
DFS(i);
}
if (i <= n) cout << "NO\n";
else {
cout << "YES\n";
for (int i = 1; i <= n; i++) {
if (i > 1) cout << " ";
cout << num[i];
}
cout << endl;
}
return 0;
}//KrK大佬真的好强
Dalao代码 #002
// From rng_58
// Rating 3074
// reason : 代码简洁明了清晰,
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
#define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
typedef long long ll;
int N;
ll a[110][110],b[110][110]; // gcd, lcm
ll c[110];
ll gcd(ll x, ll y){
return x ? gcd(y%x,x) : y;
}
bool dfs(int p, ll x){
int i;
if(c[p] != 0 && c[p] != x) return false;
if(c[p] != 0) return true;
c[p] = x;
REP(i,N) if(a[p][i] > 0){
if(a[p][i] * b[p][i] % c[p] != 0) return false;
ll y = a[p][i] * b[p][i] / c[p];
if(gcd(c[p],y) != a[p][i]) return false;
if(!dfs(i,y)) return false;
}
return true;
}
void clear(int p){
int i;
if(c[p] == 0) return;
c[p] = 0;
REP(i,N) if(a[p][i] > 0) clear(i);
}
int main(void){
int i,j,E,x,y,_a,_b;
scanf("%d%d",&N,&E);
REP(i,E){
scanf("%d%d%d%d",&x,&y,&_a,&_b); x--; y--;
a[x][y] = a[y][x] = _a; b[x][y] = b[y][x] = _b;
}
bool failed = false;
REP(i,N) if(c[i] == 0){
REP(j,N) if(b[i][j] != 0) break;
if(j == N) {c[i] = 1; continue;}
bool flag = false;
for(x=1;x*x<=b[i][j];x++) if(b[i][j]%x == 0){
if(dfs(i,x)) {flag = true; break;} clear(i);
if(dfs(i,b[i][j]/x)) {flag = true; break;} clear(i);
}
if(!flag) {failed = true; break;}
}
if(failed){
cout << "NO" << endl;
} else {
cout << "YES" << endl;
REP(i,N){
cout << c[i];
if(i == N-1) cout << endl; else cout << ' ';
}
}
return 0;
}//这是个巨佬
蒟蒻代码
#include <bits/stdc++.h>
#define ll long long
#define N 207
using namespace std;
struct node {
int v, g, l;
node(int vv, int gg, int pp) {
v = vv;
g = gg;
l = pp;
}
};
vector <node> a[N];
bool vis[N];
int ans[N];
bool dfs(int x) {
if (vis[x])
return true;
vis[x] = 1;
for (register int i = 0; i < a[x].size(); ++i) {
register node t = a[x][i];
if (t.l % ans[x] != 0)
return false;
register ll tmp = (t.g * 1LL) * (t.l * 1LL);
register int k = tmp / ans[x];
if (__gcd(k, ans[x]) != t.g)
return false;
if (vis[t.v] && k != ans[t.v])
return false;
ans[t.v] = k;
if (!dfs(t.v))
return false;
}
return true;
}
inline bool check(int x) {
node t = a[x][0];
for (register int i = t.g; i <= t.l; i += t.g) {
memset(vis, 0, sizeof vis);
ans[x] = i;
if (dfs(x))
return true;
}
return false;
}
int n, m, e1, e2, g, l;
int main() {
memset(ans, 0, sizeof ans);
scanf("%d%d", &n, &m);
for (register int i = 0; i < m; ++i) {
scanf("%d%d%d%d", &e1, &e2, &g, &l);
a[e1].push_back(node(e2, g, l));
a[e2].push_back(node(e1, g, l));
}
for (register int i = 1; i <= n; ++i) {
if (ans[i] || a[i].size() == 0)
continue;
if (!check(i)) {
puts("NO");
return 0;
}
}
puts("YES");
for (register int i = 1; i <= n; ++i) {
if (ans[i] == 0)
printf("1 ");
else
printf("%d ", ans[i]);
}
return 0;
}//本蒟蒻的代码貌似不配与这些大佬的放在一起(雾)
5 胡扯
一天一篇题解压力山大
为什么本蒟蒻认为KrK
这些大佬的码风还是有些许奇特?(虽然比大部分黑红名大佬好多了)
(又水了一篇题解)