题目概述
给出序列 {An} 和 m 个询问
解题报告
gcd和and,or一样有分块性质,由于gcd每次至少 ÷2 ,所以去重之后只有 log2n 块。
倒过来处理,假设目前处理到 i ,我们会发现
示例程序
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fr first
#define sc second
#define mp make_pair
using namespace std;
typedef long long LL;
const int maxn=1e5,maxm=1e5,maxa=1e6,Log=17;
int n,m,a[maxn+5],ID[maxn+5],blk,lst[maxa+5];LL ans[maxm+5];
pair<int,int> q[maxm+5],b[Log+5];
int gcd(int a,int b) {if (!b) return a;return gcd(b,a%b);}
LL c[maxn+5];
inline void Update(int x,int tem) {for (int p=x;p<=n;p+=p&-p) c[p]+=tem;}
inline LL Sum(int x) {LL sum=0;for (int p=x;p;p-=p&-p) sum+=c[p];return sum;}
inline void Insert(int p)
{
b[++blk]=mp(a[p],p);
for (int i=1;i<=blk;i++) b[i].fr=gcd(b[i].fr,a[p]);
int now=blk;blk=1;
for (int i=2;i<=now;i++) if (b[i].fr==b[blk].fr) b[blk].sc=b[i].sc; else
b[++blk]=b[i];
for (int i=1;i<=blk;i++) if (b[i].sc<lst[b[i].fr])
{
if (lst[b[i].fr]<=n) Update(lst[b[i].fr],-1);
Update(lst[b[i].fr]=b[i].sc,1);
}
}
inline bool cmp(int a,int b) {return q[a]>q[b];}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
while (~scanf("%d%d",&n,&m))
{
memset(c,0,sizeof(c));blk=0;for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=m;i++) ID[i]=i,scanf("%d%d",&q[i].fr,&q[i].sc);
sort(ID+1,ID+1+m,cmp);memset(lst,63,sizeof(lst));
for (int i=1,now=n;i<=m;i++)
{
while (q[ID[i]].fr<=now) Insert(now--);
ans[ID[i]]=Sum(q[ID[i]].sc)-Sum(q[ID[i]].fr-1);
}
for (int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}
return 0;
}