1 条题解

  • 0
    @ 2026-9-26 12:02:02
    • Update on 2025.1.22:修订。

    P3518 [POI2011] SEJ-Strongbox

    若 vv 是密码,则所有 ≤n\leq n 且是 gcd⁡(v,n)\gcd(v, n) 的倍数的数也是密码,因为 kv mod nkv \bmod n 取到了所有这样的数。

    证明

    设 d=gcd⁡(v,n)d = \gcd(v, n),d∣td\mid t 且 tt 不是密码,则 kv≡t(modn)kv \equiv t\pmod n 无解。根据裴蜀定理,它等价于 gcd⁡(v,n)∤t\gcd(v, n) \nmid t 即 d∤td\nmid t,矛盾。

    进一步地,若 u,vu, v 是密码,则 u′=gcd⁡(u,n)u' = \gcd(u, n) 和 v′=gcd⁡(v,n)v' = \gcd(v, n) 是密码。由裴蜀定理,gcd⁡(u′,v′)\gcd(u', v') 在模 nn 意义下能被 u′x+v′yu'x + v'y 表出,所以 gcd⁡(u′,v′)\gcd(u', v') 是密码。

    因此,设密码集合为 SS,则 d=gcd⁡(n,gcd⁡u∈Su)∈Sd = \gcd(n, \gcd_{u\in S} u)\in S。显然,SS 恰由 dd 的所有倍数组成。

    考虑枚举这个 d=gcd⁡(v,n)d = \gcd(v, n),若合法则答案即 max⁡nd\max\frac n d,即我们需要找到最小的合法的 dd。

    设 di=gcd⁡(mi,n)d_i = \gcd(m_i, n),dd 必须是密码与 nn 的 gcd⁡\gcd 即 dkd_k 的因数,其次任何 di (1≤i<k)d_i\ (1\leq i < k) 不能是 dd 的倍数。对于后者的限制,相当于在 nn 的所有因子形成的图上,一个点向它的因子连边,能被某个 did_i 到达的因子是不合法的。

    首先给所有 di (1≤i≤k)d_i\ (1\leq i\leq k) 打上标记。从大到小枚举 nn 的每个因数 cc,若 cc 被打上标记,则 cpj\frac{c}{p_j} 也应被打上标记,其中 pjp_j 表示能整除 cc 的 nn 的质因子,表示若 cc 是某个 did_i 的因数,则 cpj\frac c {p_j} 也是。

    剩下没有被打标记的 nn 的因数 dd,若 dd 能被 dkd_k 整除则合法。找到最小的这样的 dd,则答案为 nd\frac n d。

    打标记的过程可以使用哈希表实现,时间复杂度 O(n+klog⁡n+d(n)ω(n))\mathcal{O}(\sqrt n + k\log n + d(n)\omega(n)),其中 ω(i)\omega(i) 表示 ii 的质因数个数。

    #include <bits/stdc++.h>
    #include <ext/pb_ds/assoc_container.hpp>
    using namespace std;
    using namespace __gnu_pbds;
    
    #define ll long long
    inline ll read() {
    	ll x = 0; char s = getchar();
    	while(!isdigit(s)) s = getchar();
    	while(isdigit(s)) x = x * 10 + s - '0', s = getchar();
    	return x;
    }
    
    const int N = 2e4 + 5;
    ll n, k, v, ans;
    ll cpr, pr[N], cdv, dv[N];
    void dfs(int p, ll v) { // dfs 找到所有 n 的因数
    	if(p > cpr) return dv[++cdv] = v, void();
    	dfs(p + 1, v);
    	while(n / pr[p] >= v && n % (v *= pr[p]) == 0) dfs(p + 1, v);
    }
    void init() {
    	ll x = n;
    	for(ll i = 2; i * i <= x; i++)
    		if(x % i == 0) {
    			while(x % i == 0) x /= i;
    			pr[++cpr] = i;
    		} if(x > 1) pr[++cpr] = x; // 找到所有 n 的质因子
    	dfs(1, 1), sort(dv + 1, dv + cdv + 1), reverse(dv + 1, dv + cdv + 1); // 别忘了排序
    }
    gp_hash_table <ll, bool> mp; // 哈希表标记
    int main() {
    	cin >> n >> k, init();
    	for(ll i = 1; i < k; i++) mp[__gcd(read(), n)] = 1;
    	v = __gcd(read(), n);
    	for(int i = 1; i <= cdv; i++) {
    		if(mp.find(dv[i]) != mp.end()) {
    			for(int j = 1; j <= cpr; j++)
    				if(dv[i] % pr[j] == 0) mp[dv[i] / pr[j]] = 1;
    		} else if(v % dv[i] == 0) ans = n / dv[i];
    	} cout << ans << endl;
    	return 0;
    }
    
    • 1

    信息

    ID
    3863
    时间
    500ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者