zoukankan      html  css  js  c++  java
  • [Codeforces 485F] Oppa Funcan Style Remastered

    [题目链接]

               https://codeforces.com/contest/986/problem/F

    [算法]

            不难发现 , 每个人都在且仅在一个简单环中 , 设这些环长的长度分别为

            A1, A2 , A3 ... Alen, 那么有 :

            1. A1 + A2 + A3 + .. + Alen = n

            2. A1 , A2 , .. Alen为k的因子且大于或等于2

            显然 , 每一个k的因数都可以分成若干个k的质因子之和 , 因此我们可以将问题转化为求是否存在 :

            B1P1 + B2P2 + ... BmPm = n (其中,m为质因子的个数)

            当m = 0时, 显然无解

            当m = 1时 ,若n为P1的倍数 , 则有解 , 否则无解

            当m = 2时 ,   问题就转化为判断一个形如 :Ax + By = C , GCD(A,B) = 1的不定方程是否有非负整数解 , 我们可以用拓展欧几里得或其他算法解决 , 不再赘述

            当m >= 3时 , 显然 , 最小的质因子一定小于等于k ^ (1 / 3), k最大时达到10 ^ 15 , 因此 , k ^ (1 / 3)不会超过10 ^ 5 , 我们不妨建10^5个点 , 

            若(i + Pi) mod P1 = j mod P1 , 则从i向j连一条权值为Pi的边。

            然后我们从0号点开始单源最短路 ,  求得的最短路Dist[i]表示通过k的质因子组合出的,模P1余i的数中最小的 , 显然 , 若n >= Dist[n mod P1] , 问题有解 , 否则无解。

            下面我们分析整个算法的时间复杂度 :

            令Q = 50( 不同的k的个数 )

            首先 , 为了减少在分解质因数上花费的时间 , 我们需要预处理质数 ,  这将花费我们O( sqrt(K) ) )的时间 , 其中sqrt表示开根号

            对于每个询问 , 我们需要将k分解质因数 , 我们需要花费O(Q * sqrt(K) / log(K))的时间 , 其中sqrt表示开根号

            当m <= 2时我们需花费O(1) - O(logN)的时间 , 共需O(TlogN)的时间 

            当m >= 3时我们需要花费O(Q *  k ^( 1 / 3) * logk)计算单源最短路( 需使用高效的Dijkstra + 堆算法 )

            综上 , 总时间复杂度为 : O( sqrt(k) + Q * ( sqrt(k) / log(k) + k ^ (1 / 3)logk ) + TlogN) , 可以通过此题

    [代码]

              

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll MAXN = 1e18;
    const ll MAXK = 1e15;
    const ll INF = 4e18;
    const int MAXV = 3.2e7 + 5;
    const int MAXP = 2e6 + 10;
    const int MAXF = 1e5 + 10;
    const int MAXQ = 50;
    const int MAXLOG = 64;
    
    ll n,k,tot,q;
    int f[MAXV],prime[MAXP],cnt[MAXQ + 1];
    ll p[MAXQ + 1][MAXLOG],dist[MAXQ + 1][MAXF];
    ll mem[MAXQ];
    bool visited[MAXP];
    
    template <typename T> inline void read(T &x)
    {
        ll f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; 
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline ll exp_mod(ll a,ll n,ll p)
    {
            ll res = 1, b = a;
            while (n > 0)
            {
                    if (n & 1) res = res * b % p;
                    b = b * b % p;
                    n >>= 1;
            } 
            return res;
    }
    
    int main() 
    {
            
            int T;
            read(T);
            for (int i = 2; i < MAXV; i++)
            {
                    if (!f[i]) prime[++tot] = f[i] = i;
                    for (int j = 1; j <= tot; j++)
                    {
                            int tmp = i * prime[j];
                            if (tmp >= MAXV) break;
                            f[tmp] = prime[j];
                            if (f[i] == prime[j]) break; 
                    }
            }
            while (T--)
            {
                    read(n); read(k);
                    if (k == 1)
                    {
                            printf("NO
    ");
                            continue;
                    }
                    int pos = 0;
                    for (int i = 1; i <= q; i++) 
                            if (mem[i] == k) pos = i;
                    if (!pos)
                    {
                            pos = ++q;
                            mem[pos] = k; 
                            cnt[pos] = 0;
                            for (int i = 1; 1ll * prime[i] * prime[i] <= k; i++)
                            {
                                    if (k % prime[i] == 0)
                                    {
                                            p[pos][++cnt[pos]] = prime[i];
                                            while (k % prime[i] == 0) k /= prime[i];
                                    }
                            }
                            if (k != 1) p[pos][++cnt[pos]] = k;
                            if (cnt[pos] >= 3)
                            {
                                    for (int i = 0; i < p[pos][1]; i++) 
                                    {
                                            dist[pos][i] = INF;
                                            visited[i] = false;
                                    }
                                    dist[pos][0] = 0;
                                    static priority_queue< pair<ll,int> > q;
                                    q.push(make_pair(0,0));
                                    while (!q.empty())
                                    {
                                            int u = q.top().second;
                                            q.pop();
                                            if (visited[u]) continue;
                                            visited[u] = true;
                                            for (int i = 2; i <= cnt[pos]; i++)
                                            {
                                                    int to = (u + p[pos][i]) % p[pos][1];
                                                    int w = p[pos][i];
                                                    if (dist[pos][u] + w < dist[pos][to])
                                                    {
                                                            dist[pos][to] = dist[pos][u] + w;
                                                            q.push(make_pair(-dist[pos][to],to));
                                                    }
                                            }
                                    }
                            }
                    }
                    if (cnt[pos] == 1)
                    {
                            if (n % p[pos][1] == 0)
                            {
                                    printf("YES
    ");
                                    continue;
                            } else
                            {
                                    printf("NO
    ");
                                    continue;
                            }
                    }
                    if (cnt[pos] == 2)
                    {
                            ll b = n % p[pos][1] * exp_mod(p[pos][2] , p[pos][1] - 2,p[pos][1]) % p[pos][1];
                            if (b * p[pos][2] <= n) printf("YES
    ");
                            else printf("NO
    "); 
                            continue;
                    }                                         
                    int val = n % p[pos][1];
                    if (n >= dist[pos][val]) printf("YES
    ");
                    else printf("NO
    ");
            }
            
            return 0;
        
    }

            

            

  • 相关阅读:
    QT *.pri 语法学习
    qt 的相对路径说法
    openwrt 时间更新
    openwrt network 初始化
    在线配置热加载配置 go-kratos.dev 监听key 通过atomic.Value支持自动热加载
    Monkey patching
    UDP flood UDP Port Denial-of-Service Attack
    一例 Go 编译器代码优化 bug 定位和修复解析
    t
    golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期 socket
  • 原文地址:https://www.cnblogs.com/evenbao/p/9562368.html
Copyright © 2011-2022 走看看