Deebo-nun MathModel Ideal Hədiyyəsi#11857

Deebo-nun MathModel Ideal Hədiyyəsi (Həll təhlili)

Problem Müəllifi:

(De3b0o)

Hazırlayan:

Hasan Saleh (MathModel)

Redaktə edən:

(De3b0o)

Həll

Biz görürük ki, b_i \cdot x - a_i = x - a_i \bmod x , beləliklə, şərt b_i \cdot x - a_i \le c eynidir x - a_i \bmod x \le c , və biz bu şərtin bütün üçün doğru olmasını istəyirik, beləliklə, yalnız x - a_i \bmod x -in maksimum dəyəri ilə maraqlanırıq, beləliklə, yalnız a_i \bmod x-in minimum dəyəri ilə maraqlanırıq.

İndi bir tək sorğu üçün cavab, x - \min(a_i \bmod x) \le c olan ən böyük -dir.

Biz görə bilərik ki, \min(a_1,a_2,....,a_n) + c -dan böyük ola bilməz, və əgər \min(a_1,a_2,...,a_n) + c > \max(a_1,a_2,...,a_n)-dirsə, cavab \min(a_1,a_2,...,a_n) + c -dir.

Əks halda cavab \le \min(a_1,a_2,...,a_n)+c \le \max(a_1,a_2,...,a_n)-dir.

(\text{mx} = \max(a_1,a_2,...,a_n))

Beləliklə, əgər -dən -ə qədər hər üçün \min(a_i \bmod x) -i tapmağın sehrli bir yolunu təsəvvür etsək, o zaman sorğuları asanlıqla cavablandıra bilərik (ikili axtarış və ya offline istifadə edərək).

İndi sehrli yol.

Bəzi üçün, \min(a_i \bmod x) \min(\text{nxt}(0) , \text{nxt}(x) \bmod x , \text{nxt}(2x) \bmod x , \text{nxt}(3x) \bmod x , və s.)-ə bərabərdir.

Burada a_i-nin ən kiçikidir ki, a_i \ge y.

Niyə bu doğrudur?

Təsəvvür edin ki, massivdən və arasında iki element var, onları y_1<y_2 adlandıraq.

y_1 \bmod x = y_1-x \text{ və } y_2 \bmod x = y_2-x

Və çünki y1<y2, beləliklə y_1 \bmod x<y_2 \bmod x.

Beləliklə, yalnız aralığındakı ilk elementlə maraqlanırıq, eyni şey [2x,3x], [3x,4x] aralıqları üçün də keçərlidir... Asan bir həll, əvvəlcə -dan -ə qədər -i əvvəlcədən hesablamaqdır, sonra hər üçün bütün onun çoxluqlarını dövr etməkdir.

Bu O(\text{mx}\log(\text{mx}) + \text{precalculate}) tələb edir ki, bu da O(5 \times 10^9)-dən çoxdur, buna görə daha sürətli bir yol lazımdır.

Əvvəlcədən hesablamaq üçün, sadəcə iki göstərici yanaşmasından istifadə edə bilərik, beləliklə bu -dir.

Və hər üçün \min(a_i \bmod x)-i tapmaq üçün (onları ən böyük -dən ən kiçikə doğru dövr edərək), biz görə bilərik ki, -in bütün çoxluqlarını dövr etmək əvəzinə, yalnız p \cdot x-i dövr edə bilərik, burada bir asal ədəddir.

Niyə bu kifayətdir?

Çünki biz \min(a_i \bmod x)-i tapmaq istəyiriksə, əvvəlki kimi, bu \min(\text{nxt}(x) \bmod x , \min(a_i \bmod 2x) \bmod x , \min(a_i \bmod 3x) \bmod x , \min(a_i \bmod 4x) \bmod x , ...)-dir, biz görə bilərik ki, \min(a_i \bmod 4x) artıq \min(a_i \bmod 2x)-də hesablanmışdır və hər hansı qeyri-asal ədəd üçün, \min(a_i \bmod zx) artıq bütün asal faktorlarında hesablanmışdır.

Beləliklə, \min(a_i \bmod x) = \min(\text{nxt}(0) , \text{nxt}(x) \bmod x) , \min(a_i \bmod 2x) \bmod x , \min(a_i \bmod 3x)\bmod x , \min(a_i \bmod 5x) \bmod x , ...).

Amma mürəkkəblik kifayət qədər sürətlidirmi?

Yaxşı, bu metodun bir döngü istifadə edərək əməliyyat sayını hesablaya bilərik və təxminən əməliyyat olduğunu öyrənirik.

Təxminən mürəkkəblik O(\text{mx}\log(\log(\text{mx})))-dir, sübutu sizə buraxırıq.

-ə qədər bütün asal ədədləri tapmaq üçün, O(\text{mx}\log(\log(\text{mx})))-də süzgəc istifadə edə bilərik.

Beləliklə, ümumi mürəkkəblik O(2\text{mx}\log(\log(\text{mx})) + q\log(\text{mx}))-dir ki, bu da keçmək üçün kifayət qədər sürətlidir.

#include<bits/stdc++.h>
#define ll long long
#define F first
#define S second
#define in insert
#define pb push_back
#define d3 ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define cans cout << ans << "\n";
#define yes cout << "BƏLİ" << "\n";
#define no cout << "XAHİŞ ETMİR" << "\n";
#define pll pair<ll,ll>
#define lin cout << "\n";
#define mid ((l+r)/2)
#define lc (2*x)
#define rc (2*x+1)
 
using namespace std;

const ll N = 5e7+9;

int n , q , a , mn=1e9 , mx;
bool vis[N];
vector<int> p;
bool s[N];
int ans[N];

int main()
{
    d3
    for(int i = 2 ; N>i*i ; i++)
    {
        if(s[i])
            continue;
        for(ll j = i*i ; N>j ; j+=i)
            s[j]=1;
    }
    for(int i = 2 ; N>i ; i++)
    {
        if(!s[i])
            p.pb(i);
    }
    cin >> n >> q;
    for(int i = 1 ; n>=i ; i++)
        cin >> a , vis[a]=1 , mn=min(mn,a) , mx=max(mx,a);
    int lst = -1;
    for(int j = mx ; j>0 ; j--)
    {
        if(vis[j])
            lst=j;
        ans[j]=lst%j;
    }
    for(int j = mx ; j>0 ; j--)
    {
        if(j>mn)
            ans[j]=min(ans[j],mn);
        for(auto it : p)
        {
            if(it*j>mx)
                break;
            ans[j]=min(ans[j],ans[it*j]);
        }
    }
    for(int j = 1 ; mx>=j ; j++)
        ans[j]=j-ans[j];
    for(int j = mx-1 ; j>0 ; j--)
        ans[j]=min(ans[j],ans[j+1]);
    while(q--)
    {
        ll c;
        cin >> c;
        if(mn+c>mx)
        {
            c+=mn;
            cout << c << "\n";
            continue;
        }
        int l = 1 , r = mx;
        int an;
        while(l<=r)
        {
            if(ans[mid]<=c)
                an=mid,l=mid+1;
            else
                r=mid-1;
        }
        cout << an << "\n";
    }
}