[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\n");
                        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\n");
                                continue;
                        } else
                        {
                                printf("NO\n");
                                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\n");
                        else printf("NO\n"); 
                        continue;
                }                                         
                int val = n % p[pos][1];
                if (n >= dist[pos][val]) printf("YES\n");
                else printf("NO\n");
        }
        
        return 0;
    
}

        

        

猜你喜欢

转载自www.cnblogs.com/evenbao/p/9562368.html