loj#2326. 「清华集训 2017」简单数据结构【动态规划+set】

传送门

解题思路:

感觉复杂度是证不来的……不过跑得挺快……
注意序列长度不超过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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值