P14523-solution
\text{Description}
link
定义一个正整数序列是好的,当且仅当对任意正整数
对于一个长度为
-
- 若
b_i > 1 ,则b'_i = b_i (1 \le i \le m )。 -
爱莉有一个长度为
注:
\text{Solution}
考虑题目中好的序列的充要条件,容易发现是对于每个质数
知道了这个我们先考虑
若
显然每个质因数是独立的,我们对于每个质因数单独做,最后取
而对于每一个质因数,合法区间一定不可能跨过一段
做完之后扫描线即可,然后就可以获得
考虑加进来
容易发现
发现处于不同连通块的
长度为
m 的序列,对于每个质因数,序列中每个数在这个质因数上的指数在[0,r_i] 之间,并且是不降的。
考虑对序列进行差分,那么问题就变为计数元素非负且和
考虑从右往左扫描线,分三种情况讨论:
所以我们要支持区间乘,维护区间历史和,上线段树即可。
\text{Code}
历史和线段树用矩阵维护是可以过的,赞美出题人。
时间复杂度
#include<bits/stdc++.h>
#define ll long long
#define Mod 1000000007
#define N 500005
#define M 500000
using namespace std;
int read(){
int x=0,f=1,ch=getchar();
for(;!isdigit(ch);ch=getchar()) f=(ch=='-')?-1:1;
for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
int add(int x,int y){return x+y>=Mod?x+y-Mod:x+y;}
int del(int x,int y){return add(x,Mod-y);}
int mul(int x,int y){return ((ll)x*y)%Mod;}
void Add(int &x,int y){x=add(x,y);}
void Del(int &x,int y){x=del(x,y);}
void Mul(int &x,int y){x=mul(x,y);}
int n,m,q,a[N],b[N],R[N],lst[N],L[N],w[N],tmp[N];
int prime[N],tot,g[N],t[N],p[N],ans[N],pre[N],vv[N],cnt;
int Nxt[N],fac[N<<1],inv[N<<1];
bool vis[N],Vis[N];
vector<pair<int,int>>vec[N];
vector<pair<int,int>>que[N];
struct Matrix{
int c[2][2];
Matrix(){c[0][0]=c[0][1]=c[1][0]=c[1][1]=0;}
friend Matrix operator * (const Matrix &a,const Matrix &b){
Matrix c;
c.c[0][0]=add(mul(a.c[0][0],b.c[0][0]),mul(a.c[0][1],b.c[1][0]));
c.c[0][1]=add(mul(a.c[0][0],b.c[0][1]),mul(a.c[0][1],b.c[1][1]));
c.c[1][0]=add(mul(a.c[1][0],b.c[0][0]),mul(a.c[1][1],b.c[1][0]));
c.c[1][1]=add(mul(a.c[1][0],b.c[0][1]),mul(a.c[1][1],b.c[1][1]));
return c;
}
friend Matrix operator + (const Matrix &a,const Matrix &b){
Matrix c;
c.c[0][0]=add(a.c[0][0],b.c[0][0]);
c.c[0][1]=add(a.c[0][1],b.c[0][1]);
c.c[1][0]=add(a.c[1][0],b.c[1][0]);
c.c[1][1]=add(a.c[1][1],b.c[1][1]);
return c;
}
bool empty(){return (c[0][0]==1 && !c[0][1] && !c[1][0] && c[1][1]==1);}
void init(){c[0][0]=1,c[0][1]=0,c[1][0]=0,c[1][1]=1;}
}I,II;
struct Segment{
int l,r;
Matrix sum,tag;
}node[N<<2];
void getnew(int p){node[p].sum=node[p<<1].sum+node[p<<1|1].sum;}
void build(int p,int l,int r){
node[p].l=l,node[p].r=r,node[p].tag.init();
if(l==r){
node[p].sum.c[0][1]=1;
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
void spread(int p){
if(!node[p].tag.empty()){
node[p<<1].sum=node[p<<1].sum*node[p].tag;
node[p<<1|1].sum=node[p<<1|1].sum*node[p].tag;
node[p<<1].tag=node[p<<1].tag*node[p].tag;
node[p<<1|1].tag=node[p<<1|1].tag*node[p].tag;
node[p].tag.init();
}
}
void change(int p,int l,int r,Matrix v){
if(l>r) return;
if(l<=node[p].l && node[p].r<=r){
node[p].sum=node[p].sum*v;
node[p].tag=node[p].tag*v;
return;
}
spread(p);
int mid=(node[p].l+node[p].r)>>1;
if(l<=mid) change(p<<1,l,r,v);
if(r>mid) change(p<<1|1,l,r,v);
getnew(p);
}
Matrix query(int p,int l,int r){
if(l<=node[p].l && node[p].r<=r) return node[p].sum;
spread(p);
int mid=(node[p].l+node[p].r)>>1;
if(r<=mid) return query(p<<1,l,r);
else if(l>mid) return query(p<<1|1,l,r);
else return query(p<<1,l,r)+query(p<<1|1,l,r);
}
Matrix work(int v){
Matrix r;r.init(),r.c[1][1]=v;
return r;
}
void getprime(){
for(int i=2;i<=M;++i){
if(!vis[i]) prime[++tot]=i,g[i]=t[i]=i,p[i]=1;
for(int j=1;j<=tot && i*prime[j]<=M;++j){
vis[i*prime[j]]=true;
if(i%prime[j]==0){
t[i*prime[j]]=t[i]*prime[j];
g[i*prime[j]]=prime[j];
p[i*prime[j]]=p[i]+1;
break;
}
g[i*prime[j]]=t[i*prime[j]]=prime[j],p[i*prime[j]]=1;
}
}
}
int qpow(int a,int b){
int res=1;
while(b){
if(b&1) Mul(res,a);
Mul(a,a);
b>>=1;
}
return res;
}
void init(){
fac[0]=1;
for(int i=1;i<=(M<<1);++i) fac[i]=mul(fac[i-1],i);
inv[M<<1]=qpow(fac[M<<1],Mod-2);
for(int i=(M<<1);i>=1;--i) inv[i-1]=mul(inv[i],i);
}
int C(int n,int m){
if(n<m || n<0 || m<0) return 0;
return mul(fac[n],mul(inv[m],inv[n-m]));
}
int S(int n,int m){return C(n+m-1,m-1);}
int main(){
// FILE3("icedrop4");
n=read(),q=read(),getprime(),init();
I.init(),I.c[1][0]=1,II.init(),II.c[1][0]=-1;
for(int i=1;i<=n;++i) b[i]=read();
for(int i=1;i<=n;++i) if(b[i]!=1) a[++m]=b[i],pre[m]=i;
if(!m){
while(q--){
int l=read(),r=read();
printf("%d\n",mul(r-l+1,mul(r-l+2,(Mod+1)/2)));
}
return 0;
}
pre[m+1]=n+1;
for(int i=1;i<=m;++i){
int x=a[i];
while(x!=1){
if(lst[g[x]] && lst[g[x]]<i-1) vec[g[x]].push_back({L[g[x]],lst[g[x]]}),lst[g[x]]=L[g[x]]=i;
else if(lst[g[x]]) lst[g[x]]=i;
else lst[g[x]]=L[g[x]]=i;
x/=t[x];
}
}
for(int i=2;i<=M;++i) if(lst[i]) vec[i].push_back({L[i],lst[i]});
for(int i=1;i<=m;++i) R[i]=m;
for(int P=2;P<=M;++P){
if(vec[P].empty()) continue;
vec[P].push_back({m+1,m+1});
for(int mm=0;mm+1<vec[P].size();++mm){
int l=vec[P][mm].first,r=vec[P][mm].second;
if(l==n+1) break;
w[l-1]=w[r+1]=0;
for(int i=l;i<=r;++i){
w[i]=0;int x=a[i];
while(x%P==0) x/=P,++w[i];
}
for(int i=l;i<=r;++i){
int j=i;bool dn=false;
for(;j+1<=r;++j){
if(dn && w[j+1]>w[j]) break;
if(w[j+1]<w[j]) dn=true;
}
int res=j;
if(j==r){
for(int k=i;k<=j;++k) R[k]=min(R[k],vec[P][mm+1].first-1);
break;
}
while(dn && w[j]==w[j-1]) --j;
if(dn) --j;
for(int k=i;k<=j;++k) R[k]=min(R[k],res);
i=j;
}
}
}
for(int i=m-1;i>=1;--i) R[i]=min(R[i],R[i+1]);
for(int i=1;i<=m;++i) ++R[i];
for(int i=1;i<=m;++i) tmp[pre[i]]=pre[R[i]]-1;
for(int i=1;i<=n;++i) R[i]=tmp[i];
R[n+1]=n;
for(int i=n;i>=1;--i) if(!R[i]) R[i]=R[i+1];
for(int i=1;i<=q;++i){
int l=read(),r=read();
que[l].push_back({r,i});
}
for(int i=1;i<=n;++i) a[i]=b[i];
Nxt[n+1]=n+1;
for(int i=n;i>=1;--i){
if(i+1<=n && a[i+1]!=1) Nxt[i]=i+1;
else Nxt[i]=Nxt[i+1];
}
build(1,1,n);
for(int l=n;l>=1;--l){
change(1,R[l]+1,n,work(0));
int gg=-1;
if(a[l]==1 && Nxt[l]!=n+1){
int x=a[Nxt[l]],len=Nxt[l]-l,res=1;
while(x!=1){
Mul(res,S(p[x],len+1));
x/=t[x];
}
change(1,Nxt[l],n,work(res)),gg=res;
}
else if(a[l]!=1){
for(int i=l+1;i<Nxt[l];++i){
int x=a[l],len=i-l,res=1;
while(x!=1){
Mul(res,S(p[x],len+1));
x/=t[x];
}
change(1,i,i,work(res));
}
if(Nxt[l]!=n+1){
cnt=0;
{
int x=a[l];
while(x!=1){
vv[++cnt]=g[x];
x/=t[x];
}
}
{
int x=a[Nxt[l]];
while(x!=1){
vv[++cnt]=g[x];
x/=t[x];
}
}
int res=1;
for(int i=1;i<=cnt;++i){
int x=vv[i];
if(Vis[x]) continue;
Vis[x]=true;
int c1=0,c2=0;
{
int xx=a[l];
while(xx%x==0) ++c1,xx/=x;
}
{
int xx=a[Nxt[l]];
while(xx%x==0) ++c2,xx/=x;
}
int len=Nxt[l]-l-1;
Mul(res,S(abs(c1-c2),len+1));
}
for(int i=1;i<=cnt;++i) Vis[vv[i]]=false;
change(1,Nxt[l],n,work(res));
}
}
change(1,l,n,I);
for(auto [r,i]:que[l]) ans[i]=query(1,l,r).c[0][0];
if(~gg) change(1,Nxt[l],n,work(qpow(gg,Mod-2)));
}
for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
return 0;
}