1. 程式人生 > >luogu P4108 [HEOI2015]公約數數列——solution

luogu P4108 [HEOI2015]公約數數列——solution

 

 -by luogu

不會啊....

然後%了一發題解,

關鍵是

考慮序列{$a_n$}的字首gcd序列,

它是單調不升的,且最多隻會改變$log_2N$次,因為每變一次至少除2

於是,當我們詢問x時:

對每一段滿足字首gcd不變的部分;

可以用map之類的直接查詢這個區間中字首xor值等於$x\over gcd$的最小下標;

但我們還有單點修改,

考慮分塊,——隨便分個根號塊就好

對每塊

維護塊從左端到右端元素的xor和,

維護塊中左端到右端元素的gcd值,

對每個元素

維護從他所在塊的左端點到他自己的xor和與gcd值;

這樣修改隻影響一塊之內的所有元素的相關值和這一塊的相關值;

對每塊開個map

把左端到每個元素的xor值插到對應塊的map中去;

當我們查詢x時

列舉每塊,

如果到這塊之前的字首gcd等於加入這塊之後的字首gcd(設為gcd),則意味著這塊之內(從左端到右端)的所有點的字首gcd都相等,(字首gcd單調不升)

這樣的話,我們設到這塊之前的xor為$XOR_{0,L-1}$我們只需在這塊的map中查是否有某個$XOR_{l~i}$值滿足$gcd*(XOR_{0,L-1}xorXOR_{l,i})=x$即可,其效率為map的效率,$O(log_2\sqrt{N})$乘上塊數即為$O(\sqrt{N}log_2\sqrt{N})$

反之,則暴力列舉這塊中的每個元素即可,這種情況不超過log次,其總效率為$O(\sqrt{N}log_2{N})$

至於修改,則直接把對這塊所維護的資訊重新維護即可即可,塊大小為$\sqrt{N}$乘上map的效率為$O(\sqrt{N}log_2\sqrt{N})$

於是其總複雜度為$O(q\sqrt{N}log_2N)$

程式碼:

  1 #include<map>
  2 #include<cmath>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<algorithm>
  7 #define LL long long
  8
using namespace std; 9 map <int ,int >MP[350]; 10 int a[100010]; 11 int b_size,b_num; 12 int L[350]; 13 int b_gcd[350],b_xor[350]; 14 int a_gcd[100010],a_xor[100010]; 15 int n,q; 16 char s[20]; 17 int GCD(int ,int ); 18 void modify(); 19 void query(); 20 int main() 21 { 22 int i,j,k; 23 scanf("%d",&n); 24 b_size=sqrt(n); 25 for(i=1;i<=n;i++) 26 scanf("%d",&a[i]); 27 for(b_num=i=1;i<=n;b_num++,i+=b_size){ 28 L[b_num]=i; 29 a_xor[i]=a_gcd[i]=a[i]; 30 MP[b_num].insert(pair<int ,int >(a_xor[i],i)); 31 for(j=i+1;j<i+b_size&&j<=n;j++){ 32 a_xor[j]=a_xor[j-1]^a[j]; 33 a_gcd[j]=GCD(a_gcd[j-1],a[j]); 34 MP[b_num].insert(pair<int ,int >(a_xor[j],j)); 35 } 36 b_xor[b_num]=a_xor[j-1],b_gcd[b_num]=a_gcd[j-1]; 37 } 38 scanf("%d",&q); 39 for(i=1;i<=q;i++){ 40 scanf("%s",s); 41 if(s[0]=='M') 42 modify(); 43 else 44 query(); 45 } 46 } 47 int GCD(int a,int b){ 48 if(!b)return a; 49 return GCD(b,a%b); 50 } 51 void modify(){ 52 int id,x,i,j,k; 53 scanf("%d%d",&id,&x),id++; 54 for(i=j=1;j<=n;j+=b_size,i++) 55 if(j+b_size>id) 56 break; 57 MP[i].clear(); 58 a[id]=x; 59 a_xor[(i-1)*b_size+1]=a_gcd[(i-1)*b_size+1]=a[(i-1)*b_size+1]; 60 MP[i].insert(pair<int ,int >(a_xor[(i-1)*b_size+1],(i-1)*b_size+1)); 61 for(j=(i-1)*b_size+2;j<=i*b_size&&j<=n;j++){ 62 a_xor[j]=a_xor[j-1]^a[j]; 63 a_gcd[j]=GCD(a_gcd[j-1],a[j]); 64 MP[i].insert(pair<int ,int >(a_xor[j],j)); 65 } 66 b_xor[i]=a_xor[j-1],b_gcd[i]=a_gcd[j-1]; 67 } 68 void query(){ 69 LL x,xx; 70 map <int ,int >::iterator iter; 71 int i,j,k,lasxor=0,nowgcd=0,lasgcd=0; 72 scanf("%lld",&x); 73 for(i=1;i<=b_num;i++){ 74 nowgcd=GCD(b_gcd[i],lasgcd); 75 if(nowgcd==lasgcd){ 76 if(x%lasgcd){ 77 lasgcd=nowgcd,lasxor^=b_xor[i]; 78 continue; 79 } 80 xx=x/lasgcd; 81 xx^=lasxor; 82 if(xx>0x7fffffff){ 83 lasgcd=nowgcd,lasxor^=b_xor[i]; 84 continue; 85 } 86 k=xx; 87 if(MP[i].count(k)==1){ 88 iter=MP[i].find(k); 89 printf("%d\n",iter->second-1); 90 return ; 91 } 92 } 93 else{ 94 for(j=(i-1)*b_size+1;j<=n&&j<=i*b_size;j++) 95 if(1ll*(lasxor^a_xor[j])*GCD(lasgcd,a_gcd[j])==x){ 96 printf("%d\n",j-1); 97 return ; 98 } 99 } 100 lasgcd=nowgcd,lasxor^=b_xor[i]; 101 } 102 printf("no\n"); 103 }

分塊還差得遠呢

相關推薦

luogu P4108 [HEOI2015]公約數數列——solution

   -by luogu 不會啊.... 然後%了一發題解, 關鍵是 考慮序列{$a_n$}的字首gcd序列, 它是單調不升的,且最多隻會改變$log_2N$次,因為每變一次至少除2 於是,當我們詢問x時: 對每一段滿足字首gcd不變的部分; 可以用map之類的直接查詢這個區間中字首

【BZOJ4028】[HEOI2015]公約數數列 分塊

== 區間 d+ 接下來 clas sample 給定 沒有 bre 【BZOJ4028】[HEOI2015]公約數數列 Description 設計一個數據結構. 給定一個正整數數列 a_0, a_1, ..., a_{n - 1},你需要支持以下兩種操作: 1

[HEOI2015]公約數數列

turn 前綴 onclick pla post blank lan 輸入 lose 公約數數列 【問題描述】 設計一個數據結構. 給定一個正整數數列 a_0, a_1, ...,a_{n - 1},你需要支持以下兩種操作: 1. MODIFY id x: 將

bzoj4028 [HEOI2015]公約數數列(分塊+卡常?)

bubuko .com 代碼 一個 zoj wid eight height 約數 被卡常卡到懷疑人生。 思維又難又卡常(可能是我寫的太醜了)心態炸了。 最後還是照題解打的。(題解多了一個排序,似乎快了很多) 所以代碼就不發了。。。 bzoj4028 [HEOI201

[BZOJ4028][HEOI2015]公約數數列(分塊)

先發掘性質: 1.xor和gcd均滿足交換律與結合率。 2.字首gcd最多隻有O(log)個。 但並沒有什麼資料結構能同時利用這兩個性質,結合Q=10000,考慮分塊。 對每塊記錄這幾個資訊: 1.塊內所有數的gcd與異或和。 2.將塊內所有字首異或和放入一個數組排序。 查詢時從前往後遍歷每個塊

BZOJ4028 HEOI2015公約數數列(分塊)

  字首gcd的變化次數是log的,考慮對每一種gcd查詢,問題變為查詢一段區間是否存在異或字首和=x/gcd。   無修改的話顯然可以可持久化trie,但這玩意實在沒法支援修改。於是考慮分塊。   對於每一塊將其中所有塊內異或字首和排序。查詢時先看這塊與上一塊相比gcd有沒有變化,如果有對其中每個位置暴

【BZOJ4028】[HEOI2015]公約數數列(分塊)

etc operator 動態 getchar() urn 步驟 href 枚舉 line 【BZOJ4028】[HEOI2015]公約數數列(分塊) 題面 BZOJ 洛谷 題解 看一道題目就不會做系列 首先\(gcd\)最多只會有\(log\)種取值,所以我們可以暴力枚舉

[luogu P1438] 無聊的數列

sed ons das close logs src blog ide pen [luogu P1438] 無聊的數列 題目背景 無聊的YYB總喜歡搞出一些正常人無法搞出的東西。有一天,無聊的YYB想出了一道無聊的題:無聊的數列。。。(K峰:這題不是傻X題嗎) 題目描

LUOGU???】WD與數列 sam 啟發式合併

題目大意   給你一個字串,求有多少對不相交且相同的子串。   位置不同算多對。   \(n\leq 300000\) 題解   先把字尾樹建出來。   DFS 整棵樹,維護當前子樹的 right 集合。   合併兩個集合的時候暴力列舉小的那個集合,然後在另一個集合的線段樹中查詢相應的資訊計算貢

luogu P1182 數列分段Section II

二分答案 一段 col [1] 給定 初始 如何 什麽 while 題目描述 對於給定的一個長度為N的正整數數列A[i],現要將其分成M(M≤N)段,並要求每段連續,且每段和的最大值最小。 關於最大值最小: 例如一數列4 2 4 5 1要分成3段 將其如下分段

luogu p1799 數列_NOI導刊2010提高(06)

tps else return include .org 沒有 個數 ble 提高 原題鏈接 https://www.luogu.org/problem/show?pid=1799 我一開始覺得這個題真是玄學,直到我發現自己沒有寫max之後。。。(逃) f[i][j]表

luogu P3200 [HNOI2009]有趣的數列

輸入輸出格式 img ecc 空格 logs 會有 color size pan P3200 [HNOI2009]有趣的數列 2017-09-17 題目描述 我們稱一個長度為2n的數列是有趣的,當且僅當該數列滿足以下三個條件: (1)它是從1到2n共2n個整數的一個排列{

[Luogu] 廣義斐波那契數列

數列 problem 題解 get .org www. org com targe https://www.luogu.org/problemnew/show/P1349 題解:https://www.zybuluo.com/wsndy-xx/note/1152988[L

luogu P1939 【模板】矩陣加速(數列)】 題解

數列 cout spa space clas fin algo () 題解 題目鏈接:https://www.luogu.org/problemnew/show/P1939 對於矩陣推序列的式子: 由題意知: f[x+1] =1f[x] + 0f[x-1] + 1f[x-2

斐波那契公約數luogu 1306)

for ace 輸入輸出格式 () style 數列 reg range algorithm 題目描述 對於Fibonacci數列:1,1,2,3,5,8,13......大家應該很熟悉吧~~~但是現在有一個很“簡單”問題:第n項和第m項的最大公約數是多少? Update:

BZOJ 1500/Luogu 2042 - 維修數列 - [NOI2005][Splay]

題目連結:https://www.lydsy.com/JudgeOnline/problem.php?id=1500 題目連結:https://www.luogu.org/problemnew/show/P2042 Description 請寫一個程式,要求維護一個數列,支援以下 6 種操作: 請注意,

【題解】Luogu P3901 數列找不同

原題傳送門 不錯的莫隊練手題 塊數就直接取sqrt(n) 對所有詢問進行排序 排序第一關鍵詞:l所在第幾塊,第二關鍵詞:r的位置 考慮Ai不大,暴力開陣列 add時如果加之後的數量是1 總數就加1 del時如果減之後的數量是0 總數就減1 每次比較總數和該次查詢區間的長度 相等的話就把

Luogu P1962 斐波那契數列(矩陣乘法模板)

傳送門(其實就是求斐波那契數列....) 累了 明天再解釋 #include<cstdio> #define ll long long using namespace std; const ll mod = 1000000007; struct matrix {

luogu P2513 [HAOI2009]逆序對數列

luogu P2513 [HAOI2009]逆序對數列 動態規劃 f[i][j]表示前i個數有j個逆序對的方案數 f[1][0]=1 然後80分 #include<bits/stdc++.h> using namespace std; #define mod 10000 c

【矩陣乘法x2】LuoGu P1349 廣義斐波那契數列&&LNSYOJ#395遞推式字首和

這是兩道矩陣的水題 題目描述 數列f[n]=f[n-1]+f[n-2]+n+1,f[1]=f[2]=1的前n項和s[n]=f[1]+f[2]+……+f[n]的快速求法(答案取模10e9+7) 輸入格式 一個整數bb。 輸出格式 一個整數字首和。