1. 程式人生 > >【The 2017 BAPC】C題-Collatz Conjecture ---- GCD+優化去重

【The 2017 BAPC】C題-Collatz Conjecture ---- GCD+優化去重

這裡寫圖片描述

題意: 給你一個大小為n的序列,讓你求裡面所有子串的GCD,求裡面最多有多少不同的GCD。

思路: 利用集合set–tmp維護 到當前子串的最後一個元素的所有GCD,set–ans儲存所有不同種類的GCD。
分析一下為什麼不會超時,一開始以為這個演算法很暴力,覺得是O(n^2 * logn)
其實,我們猜想最暴力的情況 即,1 ,2 , 4, 8 ,16,…… ,2^n 這組資料,我們會以為
1<=n<=5e5,這樣子一定非常暴力! 其實!不是!!
為什麼呢?因為——-元素ai 要在[1,1e18]這個範圍內,所以2^n <= 10^18
兩遍同取log2 可以 轉換—–> n<= 18log2(10) 這個 數字約等於60,遠遠小於5e5,所以這個演算法複雜度差不多為O(n*18log2(10) * logn)。

AC程式碼: 臨摹超霸ORZ

#include<bits/stdc++.h>
using namespace std;
#define pb                          push_back
#define sz(x)                       int(x.size()-1)
#define all(x)                      x.begin(),x.end()
#define rep(i,s,e)                  for (int i=s;i<=e;i++)
#define rev(i,s,e)                  for (int i=e;i>=s;i--)
typedef long long LL; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const int MAXN = 5e5 + 5; LL gcd(LL a,LL b) { if(!b) return a; else return gcd(b,a%b); } set<LL> tmp1,tmp2,ans; set<LL> ::iterator it; LL a[MAXN]; int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n; cin>>n; rep(i,1,n) cin>>a[i]; int f = 0; rep(i,1,n) { if(f) { tmp1.clear(); for(it = tmp2.begin();it!=tmp2.end();it++) { LL x = gcd(a[i],*it); tmp1.insert(x); ans.insert(x); } tmp1.insert(a[i]); ans.insert(a[i]); } else { tmp2.clear(); for(it = tmp1.begin();it!=tmp1.end();it++) { LL x = gcd(a[i],*it); tmp2.insert(x); ans.insert(x); } tmp2.insert(a[i]); ans.insert(a[i]); } f ^= 1; } cout<<ans.size()<<endl; return 0; }