【考试总结】2022-01-15
人脑图灵机
看起来我的做法和主流做法不一样,不知道是不是假了
考察有几个炮弹造成 \(0\) 的贡献是不可行的,但是可以考察最小的操作次数
凑出 \(m\) 的方式有使用线段覆盖和都使用点覆盖(即不使用线段覆盖)两种,其中后者使用 ExGcd 可以求出来操作次数和最小值
前者大可直接贪心,所有的余数部分都使用线段来补满,先除 \(b\),余数除 \(a\) 最后除 \(\lfloor\frac b2\rfloor\) 上取整即可得到操作次数
Code Display
```cpp inline void exgcd(int a,int b,int &x,int &y){ if(!b) return x=1,y=0,void(); exgcd(b,a%b,x,y); int k=x; x=y; y=k-(a/b)*x; return ; } inline int calc(int a,int b,int m){ int x,y,ee=gcd(a,b); if(m%ee) return 1e18+1; m/=ee; a/=ee; b/=ee; exgcd(a,b,x,y); x*=m; y*=m; int tmp=(y%a+a)%a; x+=(y-tmp)/a*b; if(x<0) return 1e18+1; y=tmp; tmp=x%b; y+=(x-tmp)/b*a; return x+y; } inline int Use(int a,int b,int m){ int half=b/2; if(half>=a){ return (m%b+half-1)/half+m/b; } int tim=m/b; m%=b; tim+=m/a; m%=a; return tim+(m+half-1)/half; } signed main(){ freopen("turing.in","r",stdin); freopen("turing.out","w",stdout); int T=read(); while(T--){ int n=read(),m=read(),a=read(),b=read(); int half=b/2; puts(min(calc(a,b,m),Use(a,b,m))<=n?"Yes":"No"); } return 0; } ```超脑星球
朴素的费用流建图是考察每个 \(B\) 中的数字和 \(A\) 中的每个间隙连边,如果能带来对答案的增量就连边,边数是 \(\Theta(n^2)\) 级别的
如果将一个 \(B\) 中的元素 插入序列之后与其相邻的两个 \(A\) 都是大于之的,那么称其为 \(V\) 形结合,而如果都是小于之的,称为 \(?\) 形结合
直接的优化是建立两个虚拟点 \(\rm Mx,Mn\),其中 \(\rm Mx\) 表示 \(?\) 形结合,其余都去 \(\rm Mn\) 处表示
将对答案的增量写作表达式之后可以分别连边跑费用流,即 \(B\) 向 \(\rm Mn\) 连 \(-2B_i\) 同时向 \(\rm Mx\) 连 \(2B_i\),序列 \(A\) 连边权类似
\(\rm EK\) 算法是单路增广所以可以得到插入 \([1,\dots m]\) 个点时的答案,但是我们并不满足于此,所以模拟费用流被迫上场了
注意到增广路的形式有 \((\rm S\to B\to Mx/Mn\to A\to T)\) 和 \((\rm S\to B\to Mx/Mn\to A\to Mn/Mx\to A\to T)\) 两种,也就是说最多退流一次且发生在 \(\rm Mx/Mn\to Mn/Mx\) 之间
(至于退流是否单独发生在 \(B\) 侧,由于博主没有写 \(B\) 侧退流就通过了所有数据点,不确定是否需要再写上这部分)
注意这里 \(\rm Mn/Mx\) 内部的选点不会发生退流,因为这是没有对答案增量的,所以也算是对增广路经过的点数不超过 \(7\) 的感性理解吧
那么我们并不对全图进行 \(\rm spfa\) 而是根据决策的类型建立全网络流图的子图求最长路即可,每次增广的复杂度变成了 \(\Theta(k)\),本题中 \(\max k\le 10\),总复杂度降到了线性对数级别
用堆维护没有匹配中可以带来最长路的点,并在每次增广过后根据增广情况修改之
再记述细节便显得冗长了起来,那么动动你聪明的小脑瓜吧!
Code Display
```cpp const int N=5e5+10,inf=0x3f3f3f3f3f3f3f3f; int n,m,a[N],b[N],ans; int S,T,head[N],ecnt,dst[N],pre[N]; bool vis[N]; struct edge{int to,nxt,cst;}e[N<<3]; inline void adde(int u,int v,int c){ e[++ecnt]={v,head[u],c}; head[u]=ecnt; return ; } vector暗星人
问题大概可以刻画成二维平面上函数复合的形式,一种可能的做法是分块再套线段树
这种做法是最简洁的做法但是需要 \(\Theta(m\sqrt m\log n)\) 的复杂度
一个可能的优化是在查询时如果线段树子树全没有点就不再下传函数而是复合完了走人
听说标算复杂度到了一个 \(\log\) 给我震撼了!
Code Display
```cpp const int M=2e7+10,N=1e6+10,BL=2e3; int rt[N/BL],ls[M],rs[M],mx[M],a[M],b[M],tot; int bl[N],n,Q,typ,lans,ans1,ans2; inline void push(int p,int na,int nb){ b[p]=add(nb,mul(na,b[p])); ckmul(a[p],na); } const int O=3e5+10; int ul[O],ur[O],A[O],B[O]; inline void push_down(int p){ if(a[p]==1&&b[p]==0) return ; if(!ls[p]) a[ls[p]=++tot]=1; if(!rs[p]) a[rs[p]=++tot]=1; push(ls[p],a[p],b[p]); push(rs[p],a[p],b[p]); a[p]=1; b[p]=0; return ; } inline void upd(int &p,int l,int r,int id){ if(!p) a[p=++tot]=1; if(ul[id]<=l&&r<=ur[id]) return ckmax(mx[p],B[id]),push(p,A[id],B[id]); int mid=(l+r)>>1; push_down(p); if(ul[id]<=mid) upd(ls[p],l,mid,id); if(ur[id]>mid) upd(rs[p],mid+1,r,id); return ; } inline void Query(int p,int l,int r,int tar){ if(!p) return ; ckmax(ans2,mx[p]); if(l==r||(rs[p]+ls[p]==0)){ ans1=add(mul(ans1,a[p]),b[p]); return ; } push_down(p); int mid=(l+r)>>1; if(tar<=mid) Query(ls[p],l,mid,tar); else Query(rs[p],mid+1,r,tar); return ; } inline int get_int(){ int x=read(); if(typ) return x^lans; else return x; } signed main(){ freopen("dark.in","r",stdin); freopen("dark.out","w",stdout); n=read(); Q=read(); typ=read(); for(int i=1;i<=n;++i) bl[i]=(i-1)/BL+1; for(int oid=1;oid<=Q;++oid){ ul[oid]=get_int(); ur[oid]=get_int(); A[oid]=get_int(); B[oid]=get_int(); int ql=get_int(),qr=get_int(),pos=get_int(); ans1=get_int(); ans2=0; upd(rt[bl[oid]],1,n,oid); if(bl[ql]+1>=bl[qr]){ for(int i=ql;i<=qr;++i) if(ul[i]<=pos&&pos<=ur[i]){ ans1=add(mul(A[i],ans1),B[i]); ckmax(ans2,B[i]); } }else{ int bed=bl[ql]*BL,bst=(bl[qr]-1)*BL+1; for(int i=ql;i<=bed;++i) if(ul[i]<=pos&&pos<=ur[i]){ ans1=add(mul(A[i],ans1),B[i]); ckmax(ans2,B[i]); } for(int i=bl[ql]+1;i<=bl[qr]-1;++i) Query(rt[i],1,n,pos); for(int i=bst;i<=qr;++i) if(ul[i]<=pos&&pos<=ur[i]){ ans1=add(mul(A[i],ans1),B[i]); ckmax(ans2,B[i]); } } print(lans=ans1^ans2); } return 0; } ```Powered by .NET 6 on Kubernetes