zoukankan      html  css  js  c++  java
  • 【洛谷4224】[清华集训2017] 简单数据结构(暴力)

    点此看题面

    • 给定一个长度为(n)的序列,要求支持在序列前后加入或删除一个数。
    • 对于该序列的一个子序列,如果满足其中每一个数都是前一个数的倍数,就称之为上升倍数子序列。
    • 在所有操作之前及每次操作之后,求出最长上升倍数子序列长度及可能的开头个数。
    • (n,qle10^5,Vle10^6),保证每种数字最多被插入序列(10)次,且任意时刻序列中不存在相同的数

    开桶维护答案+暴力

    其实这题的想法非常暴力。。。

    由于一个数的倍数至少是它的两倍,所以答案上界不可能超过(logV)

    所以我们直接对于每个位置,开一个大小为(logV)的桶,维护之后它的所有倍数转移到它的贡献。对于总答案也类似地开上一个桶来维护(而且发现这样有一个好处,本来题目就要我们求可能的开头个数,这样就顺带维护出来了)。

    在前面插入一个数,只要枚举它的所有倍数向它转移即可,由于题目保证每种数字最多被插入(10)次,因此单次的平均复杂度可以看作(O(ln V))

    在前面删除一个数,显然不会对任何数产生影响,直接删除即可。

    在后面插入一个数,首先(O(sqrt V))求出它的所有约数,显然只有这些数可能被更新到。

    然后,我们先把它们的贡献从总答案中删去,再从小往大枚举每一个数把它们的贡献从它们的约数中删去。

    接着从当前插入的数向所有约数转移,再从大往小枚举每一个数把它们的贡献加到它们的约数中,最后把所有数的贡献重新加回总答案里。

    这个过程看起来暴力,复杂度是(O(d(V)^2))的。但同样由于每种数字最多被插入(10)次,实际运行效率还是挺高的。

    在后面删除一个数应该是一个完全一样的过程,只要把“从当前插入的数向所有约数转移”这一步改成消除当前删除的数对所有约数的贡献即可。

    具体实现可能要注意一些细节,但总体代码难度应该不高。

    代码:(O(nd(V)^2))

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define V 1000000
    #define L 20
    using namespace std;
    int n,m,p[V+5],H=N+1,T=N,s[3*N+5],f[3*N+5],g[3*N+5][L+5],ans,c[L+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void write(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc(' ');}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    I void A(int& f,int* g,CI x) {++g[x],x>f&&(f=x);}
    I void D(int& f,int* g,CI x) {--g[x];W(!g[f]) --f;}
    int d[V+5];I void F5(CI x,CI op)//在末尾加入/删除了x
    {
    	RI i,j,F,t=0;for(i=1;i*i<=x;++i) !(x%i)&&(p[i]&&(d[++t]=i),p[x/i]&&i^(x/i)&&(d[++t]=x/i));sort(d+1,d+t+1);//找出所有约数排个序
    	for(i=1;i^t;++i) D(ans,c,f[p[d[i]]]);//消去在总答案中的贡献
    	for(i=1;i^t;++i) for(F=f[p[d[i]]]+1,j=1;j^i;++j) !(d[i]%d[j])&&p[d[j]]<p[d[i]]&&(D(f[p[d[j]]],g[p[d[j]]],F),0);//消去大数对小数的转移
    	for(i=1;i^t;++i) ~op?A(f[p[d[i]]],g[p[d[i]]],2):D(f[p[d[i]]],g[p[d[i]]],2);//更新末尾对前面的转移
    	for(i=t-1;i;--i) for(F=f[p[d[i]]]+1,j=1;j^i;++j) !(d[i]%d[j])&&p[d[j]]<p[d[i]]&&(A(f[p[d[j]]],g[p[d[j]]],F),0);//加回大数对小数的转移
    	for(i=1;i^t;++i) A(ans,c,f[p[d[i]]]);//加回总答案的贡献
    }
    I void AL(CI x)//在前面加入一个数
    {
    	RI i,j;for(s[p[x]=--H]=x,g[H][f[H]=1]=1,i=2;i<=L;++i) g[H][i]=0;//清空桶
    	for(i=2*x;i<=m;i+=x) p[i]&&(A(f[H],g[H],f[p[i]]+1),0);A(ans,c,f[H]);//枚举所有倍数向它转移
    }
    I void AR(CI x) {s[p[x]=++T]=x,g[T][f[T]=1]=1,A(ans,c,1);for(RI i=2;i<=L;++i) g[T][i]=0;F5(x,1);}//在后面加入一个数
    I void DL() {D(ans,c,f[H]),p[s[H++]]=0;}//在前面删除一个数
    I void DR() {F5(s[T],-1),D(ans,c,1),p[s[T--]]=0;}//在后面删除一个数
    int main()
    {
    	RI Qt,i,x;for(read(n,m,Qt),i=1;i<=n;++i) read(x),AR(x);write(ans),writeln(c[ans]);//初始局面答案
    	for(RI op;Qt;write(ans),writeln(c[ans]),--Qt) switch(read(op),op)//每次操作后的答案
    		{case 0:read(x),AL(x);break;case 1:read(x),AR(x);break;case 2:DL();break;case 3:DR();break;}
    	return clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    新手讲排序:希尔排序
    安装部署VMware vSphere 5.5文档 (6-6) 集群和vMotion
    安装部署VMware vSphere 5.5文档 (6-5) 安装配置vCenter
    同步VDP时间
    vdp配置
    python定义常量
    OpenStack Keystone V3 简介
    nginx + uswgi +django
    安装系统
    Standard NSD file
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4224.html
Copyright © 2011-2022 走看看