codeforces 475D CGCDSSQ (st表+数论)
2016-11-08 11:15
357 查看
D. CGCDSSQ
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Given a sequence of integers a1, ..., an and q queries x1, ..., xq on
it. For each query xi you
have to count the number of pairs (l, r)such that 1 ≤ l ≤ r ≤ n and gcd(al, al + 1, ..., ar) = xi.
is
a greatest common divisor of v1, v2, ..., vn,
that is equal to a largest positive integer that divides all vi.
Input
The first line of the input contains integer n, (1 ≤ n ≤ 105),
denoting the length of the sequence. The next line contains n space separated integers a1, ..., an,
(1 ≤ ai ≤ 109).
The third line of the input contains integer q, (1 ≤ q ≤ 3 × 105),
denoting the number of queries. Then follows q lines, each contain an integer xi,
(1 ≤ xi ≤ 109).
Output
For each query print the result in a separate line.
Examples
input
output
input
output
题解:st表+数论
可以用st表预处理出区间gcd,然后O(1)查询。
我们考虑枚举左端点,随着右端点的后移,区间gcd最多变化log(n)次,因为每次变化gcd都至少要减小一半,所以显然。
那么我们可以枚举左端点,然后二分gcd每次变化的位置,用map记录答案。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define N 300003
#define LL long long
using namespace std;
int n,m,f
[20],l
;
map<int,LL> ans;
int a
;
int gcd(int x,int y)
{
int r;
while (y){
r=x%y;
x=y;
y=r;
}
return x;
}
void solve()
{
for (int i=1;i<=n;i++) f[i][0]=a[i];
for (int j=1;j<=17;j++)
for (int i=1;i<=n;i++)
if (i+(1<<j)-1<=n) f[i][j]=gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
int j=0;
for (int i=1;i<=n;i++){
if ((1<<(j+1))<=i) j++;
l[i]=j;
}
}
int calc(int x,int y)
{
int k=l[y-x];
return gcd(f[x][k],f[y-(1<<k)+1][k]);
}
int work(int pos,int l,int r,int x)
{
int ans=r+1;
while (l<=r) {
int mid=(l+r)/2;
if (calc(pos,mid)!=x) ans=min(ans,mid),r=mid-1;
else l=mid+1;
}
if (ans==r) return ans;
return ans-1;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
solve();
for (int i=1;i<=n;i++) {
int now=a[i]; int x=i;
while (true) {
int last=x;
x=work(i,last,n,now);
now=calc(i,x);
ans[now]+=x-last+1;
if (x>=n) break;
x++; now=calc(i,x);
}
}
scanf("%d",&m);
for (int i=1;i<=m;i++) {
int x; scanf("%d",&x);
cout<<ans[x]<<endl;
}
}
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Given a sequence of integers a1, ..., an and q queries x1, ..., xq on
it. For each query xi you
have to count the number of pairs (l, r)such that 1 ≤ l ≤ r ≤ n and gcd(al, al + 1, ..., ar) = xi.
is
a greatest common divisor of v1, v2, ..., vn,
that is equal to a largest positive integer that divides all vi.
Input
The first line of the input contains integer n, (1 ≤ n ≤ 105),
denoting the length of the sequence. The next line contains n space separated integers a1, ..., an,
(1 ≤ ai ≤ 109).
The third line of the input contains integer q, (1 ≤ q ≤ 3 × 105),
denoting the number of queries. Then follows q lines, each contain an integer xi,
(1 ≤ xi ≤ 109).
Output
For each query print the result in a separate line.
Examples
input
3 2 6 3 5 1 2 3 4 6
output
1 2 2 0 1
input
7 10 20 3 15 1000 60 16 10 1 2 3 4 5 6 10 20 60 1000
output
14 0 2 2 2 0 2 2 1 1
题解:st表+数论
可以用st表预处理出区间gcd,然后O(1)查询。
我们考虑枚举左端点,随着右端点的后移,区间gcd最多变化log(n)次,因为每次变化gcd都至少要减小一半,所以显然。
那么我们可以枚举左端点,然后二分gcd每次变化的位置,用map记录答案。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define N 300003
#define LL long long
using namespace std;
int n,m,f
[20],l
;
map<int,LL> ans;
int a
;
int gcd(int x,int y)
{
int r;
while (y){
r=x%y;
x=y;
y=r;
}
return x;
}
void solve()
{
for (int i=1;i<=n;i++) f[i][0]=a[i];
for (int j=1;j<=17;j++)
for (int i=1;i<=n;i++)
if (i+(1<<j)-1<=n) f[i][j]=gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
int j=0;
for (int i=1;i<=n;i++){
if ((1<<(j+1))<=i) j++;
l[i]=j;
}
}
int calc(int x,int y)
{
int k=l[y-x];
return gcd(f[x][k],f[y-(1<<k)+1][k]);
}
int work(int pos,int l,int r,int x)
{
int ans=r+1;
while (l<=r) {
int mid=(l+r)/2;
if (calc(pos,mid)!=x) ans=min(ans,mid),r=mid-1;
else l=mid+1;
}
if (ans==r) return ans;
return ans-1;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
solve();
for (int i=1;i<=n;i++) {
int now=a[i]; int x=i;
while (true) {
int last=x;
x=work(i,last,n,now);
now=calc(i,x);
ans[now]+=x-last+1;
if (x>=n) break;
x++; now=calc(i,x);
}
}
scanf("%d",&m);
for (int i=1;i<=m;i++) {
int x; scanf("%d",&x);
cout<<ans[x]<<endl;
}
}
相关文章推荐
- Codeforces Round #425 (Div. 2) Problem C Strange Radiation (Codeforces 832C) - 二分答案 - 数论
- codeforces 177B2 B2. Rectangular Game(数论)
- codeforces 449C C. Jzzhu and Apples(数论+构造)
- 51nod 1491|CodeForces 458A Golden System(数论 )
- codeforces 78C C. Beaver Game(数论+博弈)
- codeforces 10C C. Digital Root(数论)
- codeforces Unusual Sequences (数论)
- codeforces 2B B. The least round way(dp+数论)
- [CodeForces 27E] Number With The Given Amount Of Divisors (数论 + 反素数)
- CodeForces - 376C Divisible by Seven(数论:同余定理)(找规律)
- CodeForces - 58B Coins(数论)
- codeforces 471C MUH and House of Cards 数论
- Codeforces 475D CGCDSSQ 求序列中连续数字的GCD=K的对数
- codeforces 303C. Minimum Modular(数论+暴力+剪枝+贪心)
- Codeforces-798C-Mike and gcd problem(贪心+数论)
- codeforces 900D 数论+组合+容斥原理
- codeforces 300E Empire Strikes Back 数论+二分查找
- CodeForces 630 J. Divisibility(数论)
- Codeforces 711E ZS and The Birthday Paradox 数论(Legendre's定理)
- Codeforces 819 D. Mister B and Astronomers 数论