Будинок у Minecraft#12216

Будинок у Minecraft (Розбір)

Автор проблеми:

De3b0o

Підготовлено:

De3b0o

Редаговано:

Hasan Saleh (MathModel)

Рішення

Протягом рішення ми будемо припускати, що n \le m, якщо ні, ми можемо просто повернути сітку.

Ми не можемо дозволити собі симулювати кожен запит клітинка за клітинкою. Замість цього, ми обробляємо ряд за рядком.

Для фіксованого рядка , розглянемо запит (x,y,d,c,s). Всі клітинки, які задовольняють першу умову (умова відстані), формують діапазон [l,r].

Таким чином, кожен запит додає інтервал на рядку .

Ми можемо використовувати підхід з лінійним скануванням, щоб обчислити всі значення масиву для рядка .

Для рядка ми створюємо події в і r+1 для інтервалу [l,r]. Кожна подія означає: "почати додавати цей запит" або "зупинити додавання цього запиту".

Ми підтримуємо масив частот = загальна активних запитів з параметром . Ми також підтримуємо суму всіх активних .

Коли обробляємо рядок і стовпець :

  • Якщо a_{i,j}=0, тоді b_{i,j}=sum.

  • В іншому випадку, для кожного дільника з a_{i,j}, додайте до b_{i,j}.

На завершення:

ми ітеруємо по всіх рядках (1 \le i \le n), для кожного рядка ми ітеруємо по всіх запитах і знаходимо діапазон [l,r] для кожного запиту. Потім, використовуючи підхід з лінійним скануванням, ми можемо визначити значення масиву для цього рядка.

Складність:

  • Попереднє обчислення дільників: \mathcal{O}(n \cdot m \cdot \sqrt{\max A}).

  • Для кожного рядка ми ітеруємо по всіх запитах, тому це \mathcal{O}(n \cdot q).

  • Для кожної клітинки ми ітеруємо по всіх дільниках a_{x,y}, тому це \mathcal{O}(n \cdot m \cdot \max D).

Загальна складність становить \mathcal{O}(n \cdot m \cdot (\sqrt{\max A} + \max D) + n \cdot q), і оскільки n \le m, то n \le \sqrt{n \cdot m} \le 320, <= 10^6, \max D = 240.

Отже, найгірша загальна складність становить , що проходить за менше ніж 4 секунди.

Наступне - реалізація:


#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 << "YES" << "\n";
#define no cout << "NO" << "\n";
#define pll pair<ll,ll>
#define lin cout << "\n";
#define mid ((l+r)/2)
#define lc (2*x)
#define rc (2*x+1)
#define double long double
 
using namespace std;

mt19937 rnd(time(0));

const int N = 1e5+9 , NN = 1e6+9;

int q,c[N],se[100LL*N],org,sq[NN];
ll s[N],f[100LL*N],sum;
ll x[N] , y[N] , d[N] , n , m;
bool g,vis[100LL*N];
vector<int> divisors[100LL*N];

ll sqr(ll x)
{
    ll l = 0 , r = min(x,100000LL);
    ll ans;
    while(l<=r)
    {
        if(mid*mid<=x)
            ans=mid,l=mid+1;
        else
            r=mid-1;
    }
    return ans;
}

void factorize(int v)
{
    if(vis[v])
        return;
    vis[v]=1;
    for(ll i = 1 ; v>=i*i ; i++)
    {
        if(v%i==0)
        {
            divisors[v].pb(i);
            if(v/i!=i)
                divisors[v].pb(v/i);
        }
    }
}

int main()
{
    d3
    vis[0]=1;
    for(ll i = 0 ; NN>i ; i++)
        sq[i]=sqr(i);
    for(ll i = 2 ; 100LL*N>i ; i++)
    {
        if(se[i])
            continue;
        se[i]=i;
        for(ll j = i*i ; 100LL*N>j ; j+=i)
        {
            if(se[j])
                continue;
            se[j]=i;
        }
    }
    cin >> n >> m;
    if(n>m)
        swap(n,m),g=1;
    int a[n+1][m+1];
    ll b[n+1][m+1];
    memset(b,0,sizeof(b));
    vector<int> e[m+2];
    if(g)
        swap(n,m),g=0;
    if(n>m)
    {
        g=1;
        for(int i = 1 ; n>=i ; i++)
        {
            for(int j = 1 ; m>=j ; j++)
                cin>>a[j][i];
        }
        swap(n,m);
    }
    else
    {
        for(int i = 1 ; n>=i ; i++)
        {
            for(int j = 1 ; m>=j ; j++)
                cin>>a[i][j];
        }
    }
    for(int i = 1 ; n>=i ; i++)
        for(int j = 1 ; m>=j ; j++)
            factorize(a[i][j]);
    cin >> q;
    for(int qe = 1 ; q>=qe ; qe++)
    {
        cin >> x[qe] >> y[qe] >> d[qe] >> c[qe] >> s[qe];
        d[qe]*=d[qe];
        if(g)
            swap(x[qe],y[qe]);
    }
    ll mo = m*m;
    for(ll i = 1 ; n>=i ; i++)
    {
        ll de;
        int l , r;
        for(int qe = 1 ; q>=qe ; qe++)
        {
            de=d[qe]-(i-x[qe])*(i-x[qe]);
            if(de<0)
                continue;
            if(mo<=de)
                de=m;
            else if(de<NN)
                de=sq[de];
            else
                de=sqr(de);
            l=max(1LL,y[qe]-de);
            r=min(m,y[qe]+de);
            e[l].pb(qe);
            e[r+1].pb(-qe);
        }
        for(int j = 1 ; m+1>=j ; j++)
        {
            for(auto it : e[j])
            {
                if(it<0)
                    f[c[-it]]-=s[-it],sum-=s[-it];
                else
                    f[c[it]]+=s[it],sum+=s[it];
            }
            if(j==m+1)
                break;
            if(a[i][j]==0)
            {
                b[i][j]=sum;
                continue;
            }
            for(auto it : divisors[a[i][j]])
                b[i][j]+=f[it];
        }
        for(int j = 1 ; m+1>=j ; j++)
            e[j].clear();
    }
    if(g)
    {
        swap(n,m);
        for(int i = 1 ; n>=i ; i++)
        {
            for(int j = 1 ; m>=j ; j++)
                cout << b[j][i] << " ";
            lin
        }
    }
    else
    {
        for(int i = 1 ; n>=i ; i++)
        {
            for(int j = 1 ; m>=j ; j++)
                cout << b[i][j] << " ";
            lin
        }
    }
}