洛谷 P8799:[蓝桥杯 2022 国 B] 齿轮 ← 倍数筛

【题目来源】
https://www.luogu.com.cn/problem/P8799

【题目描述】
这天,小明在组装齿轮。
他一共有 n 个齿轮,第 i 个齿轮的半径为 ri,他需要把这 n 个齿轮按一定顺序从左到右组装起来,这样最左边的齿轮转起来之后,可以传递到最右边的齿轮,并且这些齿轮能够起到提升或者降低转速(角速度)的作用。

P8799

小明看着这些齿轮,突然有 Q 个疑问:能否按一定顺序组装这些齿轮使得最右边的齿轮的转速是最左边的齿轮的 qi 倍?

【输入格式】
输入共 Q+2 行,第一行为两个正整数 n,Q, 表示齿轮数量和询问数量。
第二行为 n 个正整数 r1,r2,…,rn,表示每个齿轮的半径。
后面 Q 行,每行一个正整数 qi 表示询问。

【输出格式】
Q 行,对于每个询问,如果存在至少一种组装方案满足条件,输出 YES,否则输出 NO。

【输入样例】
5 3
4 2 3 3 1
2
4
6

【输出样例】
YES
YES
NO​​​​​​​

【数据范围】
对于 15% 的数据,保证 n,Q≤100;
对于 30% 的数据,保证 n,Q≤2000;
对于 100% 的数据,保证 n≥2,n,Q≤2×10^5,ri,qi≤2×10^5。
蓝桥杯 2022 国赛 B 组 I 题。

【算法分析】
● 本题是一个经典的齿轮传动比问题。核心在于利用“相邻两个齿轮的转速比值等于齿轮半径的反比”性质 ωᵢrᵢ = ωᵢ₊₁rᵢ₊₁,​​​​​​​推出首尾齿轮转速比值为首尾齿轮半径反比,不受中间各齿轮影响。
证明:这是因为,若设各个齿轮的半径为 r₁、r₂、r₃、…、rₖ,各个齿轮的转速为 ω₁、ω₂、ω₃、…、ωₖ,则 ωₖ/ω₁ = (ωₖ/ωₖ₋₁) × …× (ω₄/ω₃) × (ω₃/ω₂) × (ω₂/ω₁) =(rₖ₋₁/rₖ) × … × (r₃/r₄) × (r₂/r₃) × (r₁/r₂) = r₁/rₖ。得证。

● 题目待求“如何组装齿轮,使得最右边的齿轮的转速是最左边的齿轮的 qi 倍”。
若 qi=1,必须存在两个半径一样的齿轮。(因为 n≥2
若 qi≠1,必须同时存在半径为 i 和 i*qi 的齿轮。
然后依据上文所证性质,通过把半径为 i 的齿轮放最右、半径为 i*qi 的齿轮放最左,中间随便放别的齿轮,即可实现题目所求。

【算法代码】

#include <bits/stdc++.h>
using namespace std;

const int N=2e5+5;
bool st[N];
int cnt[N];
bool has_same;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n,Q;
    cin>>n>>Q;
    while(n--) {
        int r;
        cin>>r;
        st[r]=true;
        cnt[r]++;
        if(cnt[r]>=2) has_same=true;
    }

    while(Q--) {
        int x;
        cin>>x;
        if(x==1) {
            cout<<(has_same?"YES\n":"NO\n");
            continue;
        }

        bool ok=false;
        for(int i=1; i*x<N; i++) {
            if(st[i] && st[i*x]) {
                ok=true;
                break;
            }
        }
        cout<<(ok?"YES\n":"NO\n");
    }

    return 0;
}

/*
in:
5 3
4 2 3 3 1
2
4
6

out:
YES
YES
NO
*/

 



【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/161995534
https://blog.csdn.net/hnjzsyjyj/article/details/161994231

 

posted @ 2026-06-24 09:07  Triwa  阅读(3)  评论(0)    收藏  举报