Collatz Conjecture

題目鏈接:Collatz Conjecture


顯然有一個3個log的做法。先預處理任意區間的gcd。用ST表即可。

然後枚舉每一個作爲最後一個位置,往前二分即可。然後是過不了的。

代碼:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+10;
int n,a[N],f[N][20];	unordered_set<int> s;
inline int ask(int l,int r){
	int len=log2(r-l+1);
	return __gcd(f[l][len],f[r-(1<<len)+1][len]);
}
inline void solve(int i){
	int j=i-1; s.insert(a[i]);
	int now=a[i];
	while(j>=1){
		int l=1,r=j;
		while(l<r){
			int mid=l+r+1>>1;
			if(ask(mid,i)!=now)	l=mid;
			else r=mid-1;
		}
		if(ask(l,i)==now)	return ;
		s.insert(now=ask(l,i));
		j=l-1;
	}
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++)	scanf("%lld",&a[i]),f[i][0]=a[i];
	for(int j=1;j<=19;j++)
		for(int i=1;i<=n-(1<<j)+1;i++)
			f[i][j]=__gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	for(int i=1;i<=n;i++)	solve(i);
	cout<<s.size();
	return 0;
}

然後,我們可以發現每個數字往前找gcd的時候,其實是和前面一個數往前面找的找到的值是有關係的。

然後對於每個數字之前能找到的數字的個數都是log的,所以我們就可以兩個log來完成了。


AC代碼:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+10;
int n,a[N],f1[N],f2[N]; unordered_set<int> s;
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]); f2[0]=0;
		for(int j=1;j<=f1[0];j++)	f2[++f2[0]]=__gcd(f1[j],a[i]),s.insert(f2[f2[0]]);
		s.insert(a[i]);	f2[++f2[0]]=a[i];	sort(f2+1,f2+f2[0]+1);
		f1[0]=f2[0]=unique(f2+1,f2+f2[0]+1)-f2-1;
		for(int j=1;j<=f1[0];j++)	f1[j]=f2[j];
	}
	cout<<s.size();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章