区间GCD、与、或 正常解法与神奇解法

题目链接:点我啊╭(╯^╰)╮

题目大意:

     n n n 个数,让你求所有连续子区间的 G C D GCD GCD 的和

解题思路:

    因为一共有 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2 个子区间,暴力是肯定不行的(别真的以为不行)
    那么 n n n 个数作 G C D GCD GCD,最多只会作 l o g n logn logn 次,也可以说会改变 l o g n logn logn 次,所以记录一下每个数下一个会改变的数的位置即可,复杂度 O ( n l o g n ) O(nlogn) Onlogn

核心:区间 G C D GCD GCD、与、或 都是这个思路,最多改变 l o g n logn logn

#include
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair  pii;
const int maxn = 5e5 + 5;
const int mod = 1e9 + 7;
int n, ans, a[maxn];
int l[maxn], v[maxn];

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]);	// j ~ i的gcd值 
			while(l[j]>1 && __gcd(a[i], v[l[j]-1])==__gcd(a[i], v[j]))
				l[j] = l[l[j]-1];
			ans = (ans + 1LL * v[j] * (j-l[j]+1)) % mod;
		}
	printf("%d", ans);
}

    那么问题来了,下面这一串代码也能神奇的ac这道题,只能说数据是个屁

#include
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);
}

你可能感兴趣的:(ACM,-,思维)