关于此题Codeforces Round 988 (Div. 3)_G. Natlan Exploring的一些总结

传送门

  • 首先肯定不能暴力建边然后求总数,会T爆
  • 首先注意到,如果当前\(a[i]\)有因子\(k\),\(k > 1\),那么对于以后出现的数\(a[j]\),如果也有因子\(k\),那么肯定就能够从\(a[i]\)\(a[j]\),于是这启示我们只需要从前往后遍历的同时,记录下各个因子对应的方案总数,然后在当前\(a[i]\)时枚举其因子,将各个因子的方案数加起来,应该就是能够到达当前\(i\)位置的方案数。
  • 然而会出现重复计数的情况,例如\(30,30\),第一个\(30\)\(2,3,5\)这三个因子的方案数全都加上了一遍,第二个\(30\)于是就重复算了两条路径。根据容斥原理,我们发现第二个\(30\)应该同时减去\(6,10,15\)的方案数,再加上\(30\)对应的方案数,于是我们在给因子加方案数的同时,也应该给不同因子的乘积也统计上方案数,而在以后统计答案时,应该对于该\(a[i]\)各个质因子能乘出来的数都统计一遍,若是由奇数个质因子相乘得到的,就应该加上该方案数,否则减去(容斥原理)。
  • 再来说如何快速统计k个质因数互相乘能得到的数。如果直接搜索的话\(2^{k}\)复杂度会炸掉,我们只需要先把k个数都乘起来,然后枚举i从1到\(\sqrt k\),通过做除法的方式统计,这样复杂度能够接受。
  • 我们先预处理出1e6范围内所有数的质因数和该数的不同质因数相乘能够得到的所有数,再根据容斥原理统计答案即可。枚举质因数时一个小细节具体看代码,不注意会T
#include<bits/stdc++.h>
    
using namespace std;
    
const int mod = 998244353;
int t;
const int N = 1e6 + 10;
int n,a[N],res;
int cnt[N],ans[N];
vector<int> h[N],g[N];

void work1(int k) {
    int x = k;
    for(int i = 2;i * i <= x;i++) {
        //注意此处应该是i * i <= x而不是i * i <= k,虽然看起来差别不大但是如果用后者会T
        if(x % i == 0) {
            h[k].push_back(i);
            while(x % i == 0) x /= i;
        }
    }
    if(x > 1) h[k].push_back(x);
}

void work2(int k) {
    int x = 1;
    for(auto i : h[k]) x *= i;
    for(int i = 2;i * i <= x;i++) {
        if(x % i == 0) {
            g[k].push_back(i);
            if(i != x) g[k].push_back(x / i);
        }
    }
    if(x > 1) g[k].push_back(x);
}
    
void solve() {
    cin >> n;
    for(int i = 1;i <= n;i++) cin >> a[i];
    for(int i = 2;i <= 1000000;i++) work1(i),work2(i);
    ans[1] = 1;
    for(int i = 1;i <= n;i++) {
        for(auto j : g[a[i]]) {
            if(h[j].size() & 1) ans[i] = (ans[i] + cnt[j]) % mod;
            else ans[i] = (ans[i] - cnt[j] + mod) % mod;
        }
        for(auto j : g[a[i]]) cnt[j] += ans[i],cnt[j] %= mod;
    }
    cout << ans[n]; 
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    t = 1;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-03-10 21:47  孤枕  阅读(10)  评论(0)    收藏  举报