LCM on Whiteboard

LCM on Whiteboard

E - LCM on Whiteboard (atcoder.jp)

题意

​ 给你 n n n个数第 i i i个数被表示为 m i m_i mi个数相乘即 p i , 1 e i , 1 × . . . × p i , m i e i , m i p_{i,1}^{e_{i,1}}\times...\times p_{i,m_i}^{e_{i,m_i}} pi,1ei,1×...×pi,miei,mi,其中任意一个 p i , j p_{i,j} pi,j均为质数,现在你可以让任意一个变成 1 1 1,操作后所有的数的最小公倍数为这次操作的结果,问你最多有多少不同的操作结果

思路

  • 思维

​ 首先可以想到一个暴力的思路,从前往后枚举每个数然后将这个数变成 1 1 1,然后看一下剩下数的 l c m ( 最 小 公 倍 数 ) lcm(最小公倍数) lcm()是否出现过即可, 对于判断一个剩下的数的 l c m lcm lcm,我们并不需要直接去求,所有数的 l c m lcm lcm的最终取决于每个 p i p_i pi的最高幂次即 e i e_i ei最大是多少,因此我们只需要记录每个质数的最大次幂是多少即可。

​ 再继续想什么时候某个质数的最高次幂会变呢,即最高次幂只有一个且当前变成 1 1 1的这个数存在这个质数的最高次幂的时候会变,如果最高次幂不止一个,将当前的数变成 1 1 1后最高次幂肯定不会变,由于最高次幂只有一个的时候会变,因此每个数如果存在某个质因子是唯一的最高次幂,那么他所构成的新的 l c m lcm lcm也是唯一的。

​ 所以只需要统计有多少个数的存在唯一的质因子即可,注意特判是否存在最开始的那个数,即当前数如果不存在任何一个唯一的质因子,那将它变成 1 1 1 l c m lcm lcm还是最初的 l c m lcm lcm,且这个 l c m lcm lcm对答案的贡献最多是 1 1 1.

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 2e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n;
    map<int, PII> mp;
    vector<vector<PII>> f(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        f[i].resize(a[i] + 1);
        for (int j = 1; j <= a[i]; j ++) {
            cin >> f[i][j].x >> f[i][j].y;
            if (mp[f[i][j].x].x < f[i][j].y) mp[f[i][j].x] = {f[i][j].y, 1};
            else if (mp[f[i][j].x].x == f[i][j].y) mp[f[i][j].x].y ++;
        }

    }
        bool f1 = false;
        int res = 0;
        for (int i = 1; i <= n; i ++) {
            bool f2 = false;
            for (int j = 1; j <= a[i]; j ++)
                if (f[i][j].y == mp[f[i][j].x].x && mp[f[i][j].x].y == 1) {
                    f2 = true;
                    break;
                }
            if (f2) res ++;
            else {
                if (!f1) f1 = true, res ++;
            }
        }
        cout << res << '\n';
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值