hdu 5381 (2015 다 교 8) -- The sum of gcd (선분 수)
4979 단어 데이터 구조
제목 대의: f (l, r) = ∑ ri = l ∑ rj = igcd (ai, ai + 1.... aj), 최초의 n 개 값 을 제시 하고 q 회 질문, 매번 출력 f (l, r) 의 값 을 묻는다.
대부분 은 모 팀 의 알고리즘 을 말 하 는데 붓 기 를 생각 하지 못 했 습 니까?
우선 임의의 a [i] 에 대해 서 는 매번 gcd 가 최소 반 으로 줄 어 들 기 때문에 뒤쪽 gcd 는 log (a [i] 를 최대 로 낮 출 수 있 습 니 다. 모든 a [i] 에 있어 서 gcd 와 같은 각 구간 을 구 할 수 있 습 니 다.
선분 트 리 로 구간 의 gcd 를 유지 하고 [l, r] 의 gcd 값 x 를 조회 할 수 있 습 니 다. i 부터 왼쪽 경계 l 을 매 거 한 다음 에 2 분 으로 gcd 와 같은 구간 의 오른쪽 경계 r 를 찾 을 수 있 습 니 다. 이것 은 a [i] 에 있어 gcd 와 같은 구간 을 얻 을 수 있 습 니 다. 그리고 다음 구간 의 왼쪽 경 계 는 r + 1 이 되 고 gcd 값 도 gcd (x, a [r + 1]) 가 되 어 이 gcd 의 오른쪽 경 계 를 계속 찾 을 수 있 습 니 다.n 번 째 숫자 를 찾 을 때 까지.이렇게 하면 i 에서 시작 하 는 gcd 와 같은 각 구간 을 얻 을 수 있다.
요구 하 는 f (l, r) 의 경우 모든 gcd (l,, r) 를 종이 에 쓰 면 f (l, r) 는 삼각형 의 구간 과.질문 하 는 l 을 큰 것 에서 작은 것 으로 정렬 하고 새로운 선분 트 리 를 만 들 며 구간 수정, 구간 조회 작업 을 완성 합 니 다. 모든 질문 의 l 에 대해 l 이상 이 고 선분 트 리 에 추가 되 지 않 은 gcd 구간 에 선분 트 리 를 추가 한 다음 에 [l, r] 의 합, 즉 f (l, r) 의 값 을 조회 합 니 다.
#include
#include
#include
#include
#include
using namespace std ;
#define LL __int64
#define maxn 10010
#define root 1,n,1
#define int_rt int l,int r,int rt
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
struct node{
int id , l , r , x ;
}p , q[maxn] ;
vector vec[maxn] ;
int n , m , a[maxn] , k ;
LL ans[maxn] ;
int cl[maxn<<2] ;
int c[maxn] ;
int read() {
int x = 0 ;
char ch ;
ch = getchar() ;
while( ch < '0' || ch > '9' )
ch = getchar() ;
while( ch >= '0' && ch <= '9' ) {
x = x*10 + ch - '0' ;
ch = getchar() ;
}
return x ;
}
int gcd(int a,int b) {
return b == 0 ? a : gcd(b,a%b) ;
}
int cmp(node a,node b) {
return a.l > b.l ;
}
void push_up(int rt) {
cl[rt] = gcd( cl[rt<<1] , cl[rt<<1|1] ) ;
}
void init(int_rt) {
if( l == r ) {
cl[rt] = read() ;
a[l] = cl[rt] ;
return ;
}
init(lson) ;
init(rson) ;
push_up(rt) ;
}
int query(int ll,int rr,int_rt) {
if( ll <= l && rr >= r ) {
return cl[rt] ;
}
int mid = (l+r)/2 , t1 = 0 , t2 = 0 ;
if( ll <= mid )
t1 = query(ll,rr,lson) ;
if( rr > mid )
t2 = query(ll,rr,rson) ;
if( t1 && t2 )
return gcd(t1,t2) ;
if( t1 ) return t1 ;
else return t2 ;
}
int search1(int l,int x) {
int low = l , mid , high = n , temp ;
while( low <= high ) {
mid = (low+high)/2 ;
if( query(l,mid,root) >= x ) {
low = mid+1 ;
temp = mid ;
}
else
high = mid-1 ;
}
return temp ;
}
LL sum[maxn<<2] , lazy[maxn<<2] ;
void push(int_rt) {
int mid = (l+r)/2 ;
sum[rt] = sum[rt<<1] + sum[rt<<1|1] ;
sum[rt] += lazy[rt<<1]*(mid-l+1) ;
sum[rt] += lazy[rt<<1|1]*(r-mid) ;
}
void update(int ll,int rr,int x,int_rt) {
if( ll > r || rr < l ) return ;
if( ll <= l && rr >= r ) {
lazy[rt] += x ;
return ;
}
update(ll,rr,x,lson) ;
update(ll,rr,x,rson) ;
push(l,r,rt) ;
}
LL getsum(int ll,int rr,LL s,int_rt) {
if( ll > r || rr < l ) return 0 ;
if( ll <= l && rr >= r ) {
return sum[rt] + (lazy[rt]+s)*(r-l+1) ;
}
return getsum(ll,rr,s+lazy[rt],lson) + getsum(ll,rr,s+lazy[rt],rson) ;
}
int main() {
int t , i , j ;
int l , r , x ;
t = read() ;
while( t-- ) {
memset(c,0,sizeof(c)) ;
memset(sum,0,sizeof(sum)) ;
memset(lazy,0,sizeof(lazy)) ;
n = read() ;
init(root) ;
vec[0].clear() ; vec[n+1].clear() ;
for(i = 1 ; i <= n ; i++) {
vec[i].clear() ;
l = r = i ;
x = a[i] ;
p.id = i ; p.x = x ;
p.l = l ; p.r = r ;
vec[i].push_back(p) ;
while( r < n ) {
x = gcd(x,a[r+1]) ;
l = r+1 ;
r = search1(i,x) ;
p.id = i ; p.x = x ;
p.l = l ; p.r = r ;
vec[i].push_back(p) ;
}
}
m = read() ;
for(i = 0 ; i < m ; i++) {
q[i].l = read() ;
q[i].r = read() ;
q[i].id = i ;
}
sort(q,q+m,cmp) ;
l = r = n+1 ;
int num = 0 ;
for(i = 0 ; i < m ; i++) {
while( l > q[i].l ) {
l-- ;
for(j = 0 ; j < vec[l].size() ; j++)
update(vec[l][j].l,vec[l][j].r,vec[l][j].x,root) ;
}
ans[ q[i].id ] = getsum(q[i].l,q[i].r,(LL)0,root) ;
}
for(i = 0 ; i < m ; i++)
printf("%I64d
", ans[i]) ;
}
return 0 ;
}
f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj)
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.