區間GCD、與、或 正常解法與神奇解法

題目鏈接:點我啊╭(╯^╰)╮

題目大意:

     nn 個數,讓你求所有連續子區間的GCDGCD 的和

解題思路:

    因爲一共有 n(n1)/2n(n-1)/2 個子區間,暴力是肯定不行的(別真的以爲不行)
    那麼 nn 個數作 GCDGCD,最多隻會作 lognlogn 次,也可以說會改變 lognlogn 次,所以記錄一下每個數下一個會改變的數的位置即可,複雜度 OnlognO(nlogn)

代碼思路:

    過於簡單

核心:區間GCDGCD、與、或 都是這個思路,最多改變 lognlogn

#include<bits/stdc++.h>
const int N=500010, P=1000000007;
int n, ans, a[N], l[N], v[N];

int gcd(int a,int b) {
	return b?gcd(b,a%b):a;
}

int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; i++) 
		scanf("%d", a+i), v[i]=a[i], l[i]=i;
		
	for(int i=1; i<=n; i++)
		for(int j=i; j; j=l[j]-1) {
			v[j] = gcd(v[j],a[i]);
			while(l[j]>1 && gcd(a[i],v[l[j]-1])==gcd(a[i],v[j]))
				l[j] = l[l[j]-1];
			ans = (1LL*v[j]*(j-l[j]+1)+ans)%P;
		}
		
	printf("%d", ans);
}

    那麼問題來了,下面這一串代碼也能神奇的ac這道題,只能說數據是個屁

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int maxn = 5e5+10;
ll n, a[maxn], ans;
int main(){
	scanf("%lld", &n);
	for(int i=1; i<=n; i++) scanf("%lld", a+i);
	ll c = a[1];
	for(int i=2; i<=n; i++) c = __gcd(c, a[i]);
	for(int i=1; i<=n; i++){
		ll x = a[i];
		for(int j=i; j<=n; j++){
			x = __gcd(x, a[j]);
			if(x==c){
				ans += 1LL*(n-j+1)*c;
				ans %= mod;
				break;
			}
			ans += x;
			ans %= mod;
		}
	}
	
	printf("%lld\n", ans);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章