日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU - 5381 The sum of gcd(莫队/线段树区间合并)

發布時間:2024/4/11 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 5381 The sum of gcd(莫队/线段树区间合并) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一個長度為 nnn 的序列,再給出 mmm 次詢問,每次詢問需要回答區間 [L,R][L,R][L,R] 內所有子區間的 gcdgcdgcd 之和。更具體的,對于詢問 [L,R][L,R][L,R],輸出 ∑l=LR∑r=lRgcd?{al,al+1,?,ar}\sum\limits_{l=L}^{R}\sum\limits_{r=l}^{R}\gcd\{a_l,a_{l+1},\cdots,a_r\}l=LR?r=lR?gcd{al?,al+1?,?,ar?}

題目分析:首先需要知道 gcdgcdgcd 的一個性質,因為 gcdgcdgcd 運算每次至少除以二,所以一個連續的區間內,最多有 lognlognlogn 個不同的 gcdgcdgcd 取值。也就是說一個連續的區間可以被分成 lognlognlogn 個連續的子區間。

本題離線的話是可以直接掛莫隊的,只需要預處理一下每個前綴和后綴的所有 gcdgcdgcd 的不同取值,在擴展區間和收縮區間時就可以將 O(n)O(n)O(n) 級別的子區間壓縮成 O(logn)O(logn)O(logn) 個子區間了,時間復雜度是 O(nlognn)O(nlogn\sqrt{n})O(nlognn?)

全網幾乎都是莫隊離線寫的,但我個人感覺用線段樹在線也是可以做的,具體難點就是在線段樹的區間合并上,考慮如何將左區間和右區間進行合并。還是需要用到上面的性質,可以將左右區間分別拆成 lognlognlogn 個連續的區間,然后 O(log2n)O(log^2n)O(log2n) 去暴力合并即可,總的復雜度是 O(nlog3n)O(nlog^3n)O(nlog3n)

代碼:
線段樹

// Problem: The sum of gcd // Contest: Virtual Judge - HDU // URL: https://vjudge.net/problem/HDU-5381 // Memory Limit: 65 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e4+100; struct Node {int l,r;LL sum; }tree[N<<2]; int a[N],st[N][20],Log[N]; void get_st(int n) {for(int i=1;i<=n;i++) Log[i]=log2(i);for(int i=1;i<=n;i++) st[i][0]=a[i];for(int i=1;i<=19;i++) for(int j=1;j+(1<<i)-1<=n;j++) st[j][i]=__gcd(st[j][i-1],st[j+(1<<(i-1))][i-1]); } int ask(int l,int r) {int k=Log[r-l+1];return __gcd(st[l][k],st[r-(1<<k)+1][k]); } int get_L(int l,int r,int R,int val) {//[l,r]找到gcd[i:R]==val的位置int ans=-1;while(l<=r) {int mid=(l+r)>>1;if(ask(mid,R)==val) r=mid-1,ans=mid;else l=mid+1;}return ans; } int get_R(int l,int r,int L,int val) {//[l,r]找到gcd[L:i]==val的位置int ans=-1;while(l<=r) {int mid=(l+r)>>1;if(ask(L,mid)==val) l=mid+1,ans=mid;else r=mid-1;}return ans; } Node merge(const Node &a,const Node& b) {Node ans;ans.l=a.l,ans.r=b.r;ans.sum=a.sum+b.sum;int l=ans.l,r=ans.r,mid=a.r;vector<int>L,R;L.push_back(mid+1),R.push_back(mid);int pos=mid;while(pos>=l) {pos=get_L(l,pos,mid,ask(pos,mid));L.push_back(pos);pos--;}pos=mid+1;while(pos<=r) {pos=get_R(pos,r,mid+1,ask(mid+1,pos));R.push_back(pos);pos++;}for(int i=1;i<(int)L.size();i++) for(int j=1;j<(int)R.size();j++) {ans.sum+=1LL*(L[i-1]-L[i])*(R[j]-R[j-1])*ask(L[i],R[j]);}return ans; } void pushup(int k) {tree[k]=merge(tree[k<<1],tree[k<<1|1]); } void build(int k,int l,int r) {tree[k]={l,r,0};if(l==r) {tree[k].sum=a[l];return;}int mid=(l+r)>>1;build(k<<1,l,mid),build(k<<1|1,mid+1,r);pushup(k); } Node query(int k,int l,int r) {if(tree[k].l>=l&&tree[k].r<=r) return tree[k];int mid=(tree[k].l+tree[k].r)>>1;if(r<=mid) return query(k<<1,l,r);else if(l>mid) return query(k<<1|1,l,r);else return merge(query(k<<1,l,r),query(k<<1|1,l,r)); } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int w;cin>>w;while(w--) {int n,m;scanf("%d",&n);for(int i=1;i<=n;i++) {scanf("%d",a+i);}get_st(n);build(1,1,n);scanf("%d",&m);while(m--) {int l,r;scanf("%d%d",&l,&r);printf("%lld\n",query(1,l,r).sum);}}return 0; }

莫隊

// Problem: The sum of gcd // Contest: Virtual Judge - HDU // URL: https://vjudge.net/problem/HDU-5381 // Memory Limit: 65 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e4+100; int size,n,m,a[N],st[N][20],Log[N]; LL ans[N]; vector<int>L[N],R[N]; struct query {int l,r,id;bool operator<(const query& a)const{if(l/size!=a.l/size)return l<a.l;else if((l/size)&1)return r<a.r;elsereturn r>a.r;} }q[N]; void get_st() {for(int i=1;i<=n;i++) Log[i]=log2(i);for(int i=1;i<=n;i++) st[i][0]=a[i];for(int i=1;i<=19;i++) for(int j=1;j+(1<<i)-1<=n;j++) st[j][i]=__gcd(st[j][i-1],st[j+(1<<(i-1))][i-1]); } int ask(int l,int r) {int k=Log[r-l+1];return __gcd(st[l][k],st[r-(1<<k)+1][k]); } int get_L(int l,int r,int R,int val) {//[l,r]找到gcd[i:R]==val的位置int ans=-1;while(l<=r) {int mid=(l+r)>>1;if(ask(mid,R)==val) r=mid-1,ans=mid;else l=mid+1;}return ans; } int get_R(int l,int r,int L,int val) {//[l,r]找到gcd[L:i]==val的位置int ans=-1;while(l<=r) {int mid=(l+r)>>1;if(ask(L,mid)==val) l=mid+1,ans=mid;else r=mid-1;}return ans; } LL left(int l,int r) {LL ans=0;for(int i=1;i<(int)R[l].size();i++) {ans+=1LL*(min(R[l][i],r)-R[l][i-1])*ask(l,R[l][i]);if(R[l][i]>r) {break;}}return ans; } LL right(int l,int r) {LL ans=0;for(int i=1;i<(int)L[r].size();i++) {ans+=1LL*(L[r][i-1]-max(L[r][i],l))*ask(L[r][i],r);if(L[r][i]<l) {break;}}return ans; } void solve() {int l=1,r=0;LL sum=0;for(int i=1;i<=m;i++){int ql=q[i].l;int qr=q[i].r;while(l>ql) sum+=left(l-1,r),l--;while(r<qr) sum+=right(l,r+1),r++;while(l<ql) sum-=left(l,r),l++;while(r>qr) sum-=right(l,r),r--;ans[q[i].id]=sum;} } void init() {get_st();for(int i=1;i<=n;i++) {L[i].clear();L[i].push_back(i+1);int pos=i;while(pos>=1) {pos=get_L(1,pos,i,ask(pos,i));L[i].push_back(pos);pos--;}}for(int i=1;i<=n;i++) {R[i].clear();R[i].push_back(i-1);int pos=i;while(pos<=n) {pos=get_R(pos,n,i,ask(i,pos));R[i].push_back(pos);pos++;}} } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);size=100;int w;cin>>w;while(w--) {scanf("%d",&n);for(int i=1;i<=n;i++) {scanf("%d",a+i);}init();scanf("%d",&m);for(int i=1;i<=m;i++) {scanf("%d%d",&q[i].l,&q[i].r);q[i].id=i;ans[i]=0;}sort(q+1,q+1+m);solve();for(int i=1;i<=m;i++) {printf("%lld\n",ans[i]);}}return 0; }

總結

以上是生活随笔為你收集整理的HDU - 5381 The sum of gcd(莫队/线段树区间合并)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。