2019 ICPC Hong Kong Station G. Game Design

Problem - G - Codeforces

Problem description: Monsters can only be born at leaf nodes and move upward. You can spend a value to build a defense tower at a node. The defense tower will prevent monsters from moving upward. A tower-building method that can make the root node unreachable by monsters at the minimum cost is a solution. Now given the number of solutions, let's construct a tree that satisfies the given number of solutions. Data limitations: Number of nodes: [2, 1e5], cost of each defense tower [1, 1e9].

Idea: It can be found that for a composite number, it can be decomposed into many prime factors, such as 8, which can be decomposed into 2 2 2these three 2s. Then the construction of the tree is:

image-20230907162202193

The number of options for this is: 2 * 2 * 2.

If it is a prime number, such as 11, you can subtract one and then add a node, and perform the composite operation method on the basis of the added node.

image-20230907162644274

It can be found: Yes 1 * 2(4-5) * 5(6-10) + 1(3-3) = 11, this +1is at the node 3. Deleting the node 2has no effect.

image-20230907162820637

It can be found that: every time you perform an operation, if it is a prime number, add -1, add a node, and add all the smallest prime factors of the prime number -1 based on that node. If it is a composite number, no additional nodes are added and all the minimum prime factors are added directly.

The proof is as follows: Commonly, the number of prime numbers within 1e5 does not exceed 9.6e3, the number of prime numbers within 1e7 does not exceed 6.7e6, and the number of prime numbers within 1e9 does not exceed 5.1e7. In the worst case, if there is a large prime number after decomposition after subtraction, then you still need to subtract 1 and then decompose. The existence of prime numbers with a difference of 2 is rare when the value is very large. The time complexity of this operation is approximate O(log(N))(taking into account the interval between prime numbers, etc.). At the same time, there is log(N) * log(N)a maximum number of nodes, and a maximum of 900. But the actual situation is much less than 900, and the limit of c is the same.

#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <ctime>
#include <random>
#include <sstream>
#include <numeric>
#include <stdio.h>
#include <functional>
#include <bitset>
#include <algorithm>
using namespace std;

// #define Multiple_groups_of_examples
#define IOS std::cout.tie(0);std::cin.tie(0)->sync_with_stdio(false);
#define dbgnb(a) std::cout << #a << " = " << a << '\n';
#define dbgtt cout<<" !!!test!!! "<<endl;
#define rep(i,x,n) for(int i = x; i <= n; i++)

#define all(x) (x).begin(),(x).end()
#define pb push_back
#define vf first
#define vs second

typedef long long LL;
typedef pair<int,int> PII;

const int INF = 0x3f3f3f3f;
const int N = 2e5 + 21;

void inpfile();

// 试除法分解质因数
vector<int> divide(int x) {
    
    
    vector<int> res;
    for(int i = 2; i <= x / i; ++i) {
    
    
        if(x % i == 0) {
    
    
            while(x % i == 0) x /= i, res.push_back(i);
        }
    }
    if(x > 1) res.push_back(x);
    return res;
}
void solve() {
    
    
    int k; cin>>k;
    vector<int> fa(N),c(N); // fa --> i节点的父亲节点是哪个    c --> 第i个点的花销
    vector<vector<int>> g(N); // 建的图
    int cnt  = 1; // 树链的编号
    
    // 进行质数分解
    /**
     * 如果小于10,直接展开成链。
     * 如果大于等于10:
     *      进行质数分解:
     *          - 是质数,多加一个节点连接 (质数-1)的分解因子所成的链
     *          - 不是质数,将所有的最小的因子作为链首,并连接到所指向的父亲节点。
    */
    auto dfs1 = [&](auto &&dfs1, int now, int fu) -> void {
    
    
        if(now < 10) {
    
     // 小于10,将树链展开。
            int father = fu;
            for(int i = 1; i <= now; ++i) {
    
    
                fa[++cnt] = father; 
                g[father].push_back(cnt);
                father = cnt; // 父亲节点要一直更新
            }
            return ;
        }
        // 分解出所有的最小因数
        auto primes = divide(now);
        if(primes.size() == 1) {
    
     // 如果是质数,加一个节点,向下递归
            fa[++cnt] = fu;
            g[fu].push_back(cnt);
            dfs1(dfs1, now-1, cnt);
        } else {
    
     // 否则,将因数暂时指向当前父亲节点,进入递归去指向它真正的父亲节点
            for(auto t: primes) {
    
    
                // 因为当前t是因子,而因子可能很大,导致不满足这个条件:2 <= N <= 1e5,因此对于大于10的质数还要进行递归找最小的
                dfs1(dfs1, t, fu);
            }
        }
    };
    dfs1(dfs1, k, 1);
    cout<<cnt<<endl;

    // 自下向上找花费
    auto dfs2 = [&](auto&&dfs2, int u) -> void {
    
    
        if(g[u].size() == 0) {
    
    
            c[u] = 1;
            return ;
        }
        for(auto y: g[u]) {
    
    
            dfs2(dfs2,y);
            c[u] += c[y];
        }
    };
    dfs2(dfs2,1);
    for(int i = 2; i <= cnt; ++i) cout<<fa[i]<<" "; puts("");
    c[1] = 1e8; // 根节点不算
    for(int i = 1; i <= cnt; ++i) cout<<c[i]<<" ";
}
int main()
{
    
    
    #ifdef Multiple_groups_of_examples
    int T; cin>>T;
    while(T--)
    #endif
    solve();
    return 0;
}
void inpfile() {
    
    
    #define mytest
    #ifdef mytest
    freopen("ANSWER.txt", "w",stdout);
    #endif
}

Template - Mathematics - Number Theory - Common Knowledge of Number Theory - KisekiPurin2019 - Blog Park (cnblogs.com)

Graph Editor (csacademy.com)

Guess you like

Origin blog.csdn.net/qq_63432403/article/details/132741403