解题思路:
感觉复杂度是证不来的……不过跑得挺快……
注意序列长度不超过20,所以也比较暴力,就是记录每个值的位置,以每个点开头的最长长度和每个长度对应的最小结尾位置,用set维护以每个点为结尾的最长序列开头位置,用桶维护答案……向左加就枚举倍数更新,向右加就枚举约数更新……每次操作答案最多加减一是个很好的性质。
#include<bits/stdc++.h>
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=1000005,INF=1e9;
int n,m,Q,ans,a[N],pos[N],f[N],cnt[N],ed[N][21],d[N];
set<int>st[N];set<int>::iterator it;
void add_l(int x)
{
for(int i=1;i<=20;i++)ed[x][i]=INF;
f[x]=1,ed[x][1]=x,pos[a[x]]=x;
for(int i=2*a[x];i<=m;i+=a[x])if(pos[i])
{
int y=pos[i];
for(int j=1;j<=f[y];j++)ed[x][j+1]=min(ed[x][j+1],ed[y][j]);
f[x]=max(f[x],f[y]+1);
}
ans=max(ans,f[x]),++cnt[f[x]],st[ed[x][f[x]]].insert(x);
}
void del_l(int x)
{
--cnt[f[x]],st[ed[x][f[x]]].erase(x),pos[a[x]]=0;
if(!cnt[f[x]])ans--;
}
void add_r(int x)
{
for(int i=1;i<=20;i++)ed[x][i]=INF;
cnt[f[x]=1]++,st[ed[x][1]=x].insert(x),pos[a[x]]=x,*d=0;
for(int i=1;i*i<=a[x];i++)if(a[x]%i==0)
{
if(pos[i])d[++*d]=i;
if(i*i!=a[x]&&pos[a[x]/i])d[++*d]=a[x]/i;
}
sort(d+1,d+*d+1);
for(int i=*d;i;i--)
for(int j=i+1;j<=*d;j++)if(d[j]%d[i]==0&&pos[d[j]]>pos[d[i]])
{
int a=pos[d[i]],b=pos[d[j]];
if(f[a]<f[b]+1)
{
st[ed[a][f[a]]].erase(a),--cnt[f[a]];
f[a]++,ed[a][f[a]]=x;
++cnt[f[a]],st[ed[a][f[a]]].insert(a);
break;
}
}
if(cnt[ans+1])ans++;
}
void del_r(int x)
{
pos[a[x]]=0,--cnt[1];
for(it=st[x].begin();it!=st[x].end();it++)
{
int y=*it;if(y==x)continue;
ed[y][f[y]]=INF;
--cnt[f[y]--],++cnt[f[y]];
st[ed[y][f[y]]].insert(y);
}
st[x].clear();
if(!cnt[ans])ans--;
}
int main()
{
//freopen("lx.in","r",stdin);
n=getint(),m=getint(),Q=getint();
int l=Q+1,r=Q+n;
for(int i=l;i<=r;i++)a[i]=getint();
for(int i=r;i>=l;i--)add_l(i);
cout<<ans<<' '<<cnt[ans]<<'\n';
while(Q--)
{
int op=getint();
if(op==0)a[--l]=getint(),add_l(l);
else if(op==1)a[++r]=getint(),add_r(r);
else if(op==2)del_l(l++);
else del_r(r--);
cout<<ans<<' '<<cnt[ans]<<'\n';
}
return 0;
}