24 Eylül 2014 Çarşamba

Powerful Array

Enes Öncü' ye teşekkür ederiz.

Soru Metni

Size n elemandan oluşan bir dizi ve t adet l ve r ikilisi veriliyor.
Sizden her sorgu için dizinin l ve r aralığındaki altdizisinin Kuvvet Değeri isteniliyor.
Bir altdizideki Kuvvet Değeri şöyle tanımlanıyor:
Bir altdizideki s sayısının geçme sayısı Ks olsun. Tüm farklı s sayıları için Ks*Ks*s toplamı bize altdizinin Kuvvet degerini veriyor.

Size verilen t tane altdizinin Kuvvet Değerlerini ayrı ayrı bulmaniz.

1<=n,t<=200000
Tüm sayılar 1000000'den küçük.

Örnek 1:
3 2
1 2 1
1 2
1 3
Çıktı 1:
3
6

Örnek 2:
8 3
1 1 2 2 1 3 1 1
2 7
1 6
2 7
Çıktı 2:
20
20
20

İkinci örnek ilk sorgu için açıklama:

2. ve 7. indisleri arasında s = 1,2,3 olabiliyor.
Bu aralıkta:
K1 = 3
K2 = 2
K3 = 1 olur.
K1*K1*1+K2*K2*2+K3*K3*3 = 20 olur.

Soru Linki: http://codeforces.com/problemset/problem/86/D

Çözüm metni:

Soruyu çözmeye başlamadan önce tüm sorguları okuyoruz.

Başta tüm sorguları şu şarta göre sıralıyoruz:
a sorgusuyla b sorgusu elimizde olsun.
a -> l1,r1
b -> l2,r2
Eğer diziyi K'lik gruplara ayırdığımızda l1 ve l2 aynı gruptaysa: r1 ve r2 den hangisi küçükse onu daha önce cevaplıyoruz.
Eğer diziyi K'lik gruplara ayırdığımızda l1 ve l2 farklı gruptaysa: l1 ve l2 den küçük olanını önce cevaplıyoruz.

Aslında bundan sonrası amele bir çözüm olacak.

Elimizde sol,sag aralığı ve bu aralıgın cevabı olsun.
Sıradaki sorgu l,r aralığı olsun.

Eğer sağ imleci r den gerideyse sağ imlecini ilerletip cevabı güncelleriz.
Eğer sag imleci r den ilerideyse sağ imlecini geriye çekip cevabı güncelleriz.
Eğer sol imleci l den gerideyse sol imlecini ilerletip cevabı güncelleriz.
Eğer sol imleci l den ilerideyse sol imlecini geriye çekip cevabı güncelleriz.

Peki cevabı nasıl güncelleriz?

Bir dizide şu anda elimizde bulunan sayıların bu aralıkta geçme sayılarını tutarız. Yani her s için bi tane dizide Ks'i tutarız.
Bu diziye P[] diyelim.
Yeni bir eleman x ekleneceğinde cevaptan P[x]*P[x]*x çıkartır P[x]'i 1 artırır son olarak cevaba P[x]*P[x]*x ekleriz.
Altdizideki bir eleman x çıkartılacağında cevaptan P[x]*P[x]*x çıkartır P[x]'i 1 azaltır son olarak cevaba P[x]*P[x]*x ekleriz.

Peki ya maliyet ne oluyor?

Tum K'lık grupları ayrı ayrı inceleyelim.
Bir gurptaki r ler küçükten büyüğe sıralıdır.
Yani sağ imlecini bir grupta toplamda en fazla n kere ilerletebiliriz. Bu da n/K grup için n*n/K olur.
Bir gruptaki herhangi bir l den diğerine geçerken en fazla K işlem yaparız. Bu da t adet sorgu için t*K olur.

Bir gruptan diğer gruba geçerken l imleci en fazla 2*K kadar ilerleyebilir. n/K grup için 2*n maliyet gelir.
Bir gruptan diğer gruba geçerken r imleci en fazla n kadar geriye gelebilir. n/K grup için n*n/K maliyet gelir.

Peki K'yı kaç seçmeliyiz?

n*n/K+t*K yı en küçük yapabilmek için K'yı sqrt(n) seçmeliyiz.

Yani toplamda maliye O( (n+t)*sqrt(n) ) olur.


Çözüm Kodu:

#include <bits/stdc++.h>

#define st first
#define nd second
#define mp make_pair
#define lli long long int
#define FP( ii,aa,bb ) for( int ii=aa;ii<=bb;ii++ )

#define sqrtn 450

using namespace std;

int n,t,s[2000000],a[300000];
lli res,ans[300000],sqr[3000000];
pair< pair< int,pair<int,int> >,int > arr[300000];

int main(){

ios_base::sync_with_stdio( false );

cin >> n >> t;
FP( i,1,n ) cin >> a[i],sqr[i]=(lli)i*i;

FP( i,1,t ){
cin >> arr[i].st.nd.nd >> arr[i].st.nd.st,arr[i].nd = i;
arr[i].st.st = (arr[i].st.nd.nd-1)/sqrtn;
}

sort( arr+1,arr+t+1 );

int l=0,r=0;

FP( i,1,t ){
while( r<arr[i].st.nd.st ){
r++;
res -= a[r]*sqr[s[a[r]]];
s[a[r]]++;
res += a[r]*sqr[s[a[r]]];
}
while( r>arr[i].st.nd.st ){
res -= a[r]*sqr[s[a[r]]];
s[a[r]]--;
res += a[r]*sqr[s[a[r]]];
r--;
}
while( l<arr[i].st.nd.nd ){
res -= a[l]*sqr[s[a[l]]];
s[a[l]]--;
res += a[l]*sqr[s[a[l]]];
l++;
}
while( l>arr[i].st.nd.nd ){
l--;
res -= a[l]*sqr[s[a[l]]];
s[a[l]]++;
res += a[l]*sqr[s[a[l]]];
}
ans[arr[i].nd] = res;
}

FP( i,1,t )
cout << ans[i] << endl;

}

Hiç yorum yok:

Yorum Gönder