CF60C Mushroom Strife 解题报告

CF60C Mushroom Strife 解题报告

1 题目链接

https://codeforces.com/problemset/problem/60/C

2 题目整理

题目 :蘑菇冲突

题目描述

帕夏和阿基姆正在绘制一张地图——草坪是地图的顶点,连接草坪的道路是地图的边。他们决定用以下方式对每片草坪上的蘑菇数量进行编码:在两片草坪之间的每一条边上,他们写下两个数字,即这些草坪上蘑菇数量的最大公约数(GCD)和最小公倍数(LCM)。但有一天,帕夏和阿基姆就这些蘑菇发生了争执,并撕毁了地图。帕夏只剩下一部分,只有m条路。你的任务是帮助帕夏——利用他拥有的地图恢复每片草坪上蘑菇的数量。由于结果不一定是唯一的,请帮助帕夏恢复任何一种蘑菇,或报告这种蘑菇排列不存在。保证初始地图上的道路数量不少于1,且不超过 1 0 6 10^6 106

输入格式

第一行包含两个数字n和m,这是我们知道的草坪和道路的数量。下面m组数据中每一组包含四个数字,即道路连接的草坪数量、这些草坪上蘑菇数量的最大公因数和最小公倍数。

可以保证的是,没有任何道路将草坪连接到自身,也没有两个草坪通过一条以上的道路连接。

输出格式

答案的第一行应是“YES”或“NO”,说明是否可能执行该安排。如果答案是“YES”,请在下一行打印相应草坪上蘑菇的数量。

样例输入1
1 0
样例输出1
YES
1
样例输入2
2 1
1 2 1 3
样例输出2
YES
1 3
样例输入3
3 2
3 2 1 2
3 1 1 10
样例输出3
YES
5 1 2
样例输入4
2 1
1 2 3 7

样例输出4
NO
数据范围

对于 100 % 100\% 100%的数据:
1 ≤ n ≤ 100 1 \le n \le 100 1n100
1 ≤ m ≤ n × ( n + 1 ) 2 1 \le m \le \frac{n \times (n + 1)}{2} 1m2n×(n+1)
1 ≤ G C D , L C M ≤ 1 0 6 1 \le GCD, LCM \le 10^6 1GCDLCM106

3 题意分析

3.1 题目大意

给定一个n个点,m条边的无向图,每个点上有一个数值,每条边上标记着它连接的两个点的GCD和LCM。请给出一种点上的数值的构造。若没有,输出 " N O " "NO" "NO",否则 “ Y E S ” “YES” YES加构造

3.2 样例分析

如上所述。

4 解法分析

先考虑数据范围,n小于100,所以题目应该可以用暴力或深搜来做。再分析题目。有公式: a × b = G C D ( a , b ) ∗ L C M ( a , b ) a \times b = GCD(a,b) * LCM(a,b) a×b=GCD(a,b)LCM(a,b),所以只要确定了a,就能推出b。类似的,只要确定一个连通快里的一个数,就能推出此连通块内的所有数。那么,我们可以先枚举其中一个数,再推出其他的数,看可不可行。这样,整道题就轻松了许多。

AC代码

ACCode #001
// From nvmdava
// Rating 2447
// reason : 思路清晰,代码简洁易懂
#include <bits/stdc++.h>
using namespace std;

struct Edge{
	int to;
	long long gcd, lcm;
	Edge(int _u, int _gcd, int _lcm){
		to = _u;
		gcd = _gcd;
		lcm = _lcm;
	}
};

vector<Edge> to[105];
long long a[105];

void clr(int v){
	a[v] = 0;
	for(auto x : to[v])
		if(a[x.to])
			clr(x.to);
}

bool dfs(int v){
	for(auto x : to[v]){
		if(a[x.to]){
			if(__gcd(a[v], a[x.to]) != x.gcd) return 0;
			if(a[v] * a[x.to] != x.lcm * x.gcd) return 0;
			continue;
		}
		a[x.to] = x.lcm * x.gcd / a[v];
		if(a[x.to] <= 0 || a[x.to] > 1000000) return 0;
		if(__gcd(a[v], a[x.to]) != x.gcd) return 0;
		if(a[v] * a[x.to] != x.lcm * x.gcd) return 0;
		if(!dfs(x.to)) return 0;
	}
	return 1;
}

int main(){
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	int n, m;
	cin>>n>>m;
	while(m--){
		int v, u, g, l;
		cin>>v>>u>>g>>l;
		to[v].push_back(Edge(u, g, l));
		to[u].push_back(Edge(v, g, l));
	}
	
	for(int i = 1; i <= n; i++){
		if(a[i]) continue;
		for(int j = 1; j <= 1000000; j++){
			a[i] = j;
			if(!dfs(i)) clr(i);
			else break;
		}
		
		if(!a[i]){
			cout<<"NO";
			return 0;
		}
	}
	cout<<"YES\n";
	for(int i = 1; i <= n; i++)
		cout<<a[i]<<' ';
}
ACCode #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;
}

ACCode #003
// From KrK
// Rating 2787
// reason : 思路清晰,代码简单易懂,可读性强
#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: SCA60C是一款先进的电子产品,它是一种轴流风机控制器。这款产品是专门设计用来控制和调节轴流风机的工作,以满足不同的空气流量需求。它适用于各种领域和行业,包括工业、商业和住宅。 这个中文说明书提供了关于SCA60C控制器的详细信息,以帮助用户了解如何正确操作和安装该设备。说明书首先提供了产品的基本介绍,包括主要特点和功能。用户可以了解到SCA60C具有自动风速调节、定时开关、温度显示等功能,以及其紧凑的设计和易于安装的特点。 接下来,说明书详细介绍了SCA60C的操作步骤。用户可以了解到如何使用控制器来调整风机的转速和风速,以及如何选择合适的操作模式。此外,说明书还提供了关于设备维护和保养的建议,以确保其正常运行和延长使用寿命。 对于需要安装SCA60C的用户,说明书还提供了详细的安装指南。它包括必要的安全措施和逐步说明,以确保正确连接控制器和风机,并避免任何潜在的危险。此外,说明书还提供了有关供电要求和连接方式的信息,以及一些常见问题的解决方法。 总的来说,SCA60C中文说明书为用户提供了全面而详细的信息,以帮助他们正确使用和安装该产品。无论是初次接触这款设备的用户,还是有经验的用户,他们都可以从这个说明书中获得所需的指导和支持。通过这本说明书,用户可以更好地理解SCA60C的功能和操作方法,并充分发挥其功能,提高风机控制的效率和便利性。 ### 回答2: sca60c是一种电子设备,它是一种多功能的智能手表。这款手表具有时钟、计时器、闹钟、计步器、心率检测、睡眠监测以及通知提醒等功能。 首先,sca60c手表具有精确的时钟功能,可以显示当前时间,并且还可以设置多个闹钟,提醒您重要的日程安排。 其次,sca60c还配备了一个计时器功能,可以帮助您准确计算时间,非常实用。 此外,sca60c还具有计步器功能,可以记录您的步数、距离和消耗的卡路里,通过这些数据,您可以更好地了解自己的运动情况。 另外,sca60c还使用心率检测技术,在您佩戴手表的同时,可以实时监测您的心率,帮助您了解自己的健康状况。 还有一个重要的功能是睡眠监测,sca60c可以监测您的睡眠质量,通过分析您的睡眠数据,它可以帮助您改善睡眠习惯。 除了以上功能,sca60c还支持通知提醒,当您连接手机后,手表可以实时显示手机来电、短信和社交媒体的通知。 总之,sca60c是一款功能强大的智能手表,它需要通过简单易懂的中文说明书来指导用户操作和正常使用。这样,用户可以更好地了解手表的功能、使用方法和注意事项,以充分发挥其功能,提高用户体验。同时,说明书还应包含维护手表所需的注意事项,以确保手表的使用寿命和性能。 ### 回答3: SCA60C,是一款具有先进功能和便捷操作的电子产品。下面是对SCA60C中文说明书的简要回答。 SCA60C 中文说明书中详细介绍了该产品的功能、特点和使用方法。首先,它具备高精度的测量功能,能够精确测量物体的重量、长度和体积等多个参数。其次,该产品采用先进的传感技术,能够自动识别并适应不同的测量环境,确保测量结果的准确性和可靠性。 SCA60C 还具有便捷的操作方式,用户只需按照说明书中的步骤进行操作,即可轻松完成测量和设定。同时,该产品还配备有一块大屏幕显示屏,可以清晰地显示测量结果和操作信息,方便用户进行实时监测和控制。 此外,SCA60C 还具备一些智能化的特点,例如自动关机、数据存储和数据传输等功能。自动关机功能可以在一段时间内无操作时自动关闭电源,以节省能源和延长电池寿命;数据存储功能可以将测量结果保存在内部存储器中,方便用户随时查阅和导出;而数据传输功能可以通过USB接口将测量数据导出到电脑或其他设备上进行分析和处理。 总的来说,SCA60C 是一款功能强大、操作简便的电子产品,适用于各种测量场景。无论是在工业生产中的质量控制,还是在家庭中的日常使用,SCA60C 都能满足用户的需求,并提供准确可靠的测量数据。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值