CF60C Mushroom Strife 解题报告

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这些大佬的码风还是有些许奇特?(虽然比大部分黑红名大佬好多了)
(又水了一篇题解)

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值