Bayan 2015 Contest Warm Up, problem: (D) CGCDSSQ
题意:q次询问x,问存在多少组 [ l , r ] [l,r] [l,r]区间使得 g c d ( a l , a l + 1 , … … a r ) = x gcd(a_l,a_{l+1},……a_r)=x gcd(al,al+1,……ar)=x
个人想法:极像线段树的题面(不知道能不能做反正不会……
我的想法从每个数字开始遍历,如果
g
c
d
[
l
,
r
]
=
1
,
则
g
c
d
[
l
,
r
+
1
]
gcd[l,r]=1,则gcd[l,r+1]
gcd[l,r]=1,则gcd[l,r+1]肯定=1,所以此时直接break,往gcd为1的map上加
但是其实最坏情况就是有很多个连续数字是相等的情况,这样就会一直遍历下去达到 O ( n 2 ) O(n^2) O(n2)的复杂度…所以直接TLE死掉了
错误代码:(小朋友请勿模仿
int gcd(int a,int b){ return b?gcd(b,a%b):a;}
map<int ,ll > M;
int a[maxn];
int main()
{
int n;
scanf("%d",&n);
rep(i,1,n)scanf("%d",&a[i]);
rep(i,1,n)
{
M[a[i]]++;
int g=a[i];
int j=i+1;
while(j<=n&&g!=1)
{
g=gcd(g,a[j]);
M[g]++;
j++;
}
if (n-j+1>=0)M[1]+=(n-j+1);
}
int m,x;
scanf("%d",&m);
while(m--)
{
scanf("%d",&x);
WW(M[x]);
}
return 0;
}
大神思路:考虑到 1 ≤ a i ≤ 1 0 9 1\leq a_i \leq 10^9 1≤ai≤109,所以每个数字的gcd不会超过31, i + 1 i+1 i+1位置的gcd贡献就是从 i i i位置的贡献基础上来的,所以可以递归求解,这个递归求解加上map的使用简直是无敌
正解:
map<int, ll> ans;
map<int, ll> now;
map<int, ll> pre;
map<int, ll>::iterator it;
int a[maxn];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main()
{
int n;
ans.clear();
scanf("%d",&n);
rep(i,1,n)scanf("%d",&a[i]);
rep(i,1,n)
{
swap(pre,now);
now.clear();
for (it=pre.begin();it!=pre.end();it++)
{
now[gcd(it->first,a[i])]+=it->second;
}
now[a[i]]++;//自身也可以单独造成贡献
for (it=now.begin();it!=now.end();it++)
{
ans[it->first]+=it->second;
}
}
int q,x;
scanf("%d",&q);
while(q--)
{
scanf("%d",&x);
WW(ans[x]);
}
return 0;
}