为什么爆成这样还要写记录。abc420&&cf2133
省流:abc 没质量;cf 没实力。
AT_abc420_f kirinuki
你早说你是 \(O(NM)\) 的不就行了嘛。
一眼感觉不太好计数,但是 \(NM \le 5\times 10^6\) 就很有意思。直接上分治,我们去分治列,则现在只需要解决 \(l_y \in [l,mid]\land r_y \in (mid,r]\) 时的计数。去枚举 \(l_x=i\),记 \(nxt_{i,j}\) 表示第 \(i\) 列第 \(j\) 行能够向下拓展的最远距离,满足中间所有点都是 .
。那么分治枚举 \(l_y = y\) 时,可能的矩形宽不会超过 \(\min\limits_{k=y}^{mid}nxt_{k,i}\),因为一旦宽比这个大就说明至少存在一列包含了至少一个 #
。然后就是板子了,可以通过双指针找到 \(y'\),满足对于所有 \(r_y \in (mid,y']\),都有 \(\min\limits_{k=mid+1}^{r_y}nxt_{k,i} \ge \min\limits_{k=y}^{mid}nxt_{k,i}\),而 \(r_y \in (y',r]\) 都有 \(\min\limits_{k=mid+1}^{r_y}nxt_{k,i} < \min\limits_{k=y}^{mid}nxt_{k,i}\)。记 \(mi=\min\limits_{k=y}^{mid}nxt_{k,i}\),那么 \(r_y \in (mid,y']\) 时的贡献就是所有长在区间 \([mid+1-y+1,y'-y+1]\),宽在区间 \([1,mi]\) 且面积不超过 \(K\) 的矩形数量。这个满足:\(cnt=\sum\limits_{i=mid+1-y+1}^{y'-y+1}\min(mi,\lfloor\frac{K}{i}\rfloor)\),差分一下就只需要维护 \(\sum\limits_{i=1}^{a}\min(b,\lfloor\frac{K}{i}\rfloor)\)。由于 \(a \le m,b\le n\),所以预处理的时间复杂度 \(O(NM)\)。对于 \(r_y\in (y',r]\) 的情况,相当于是在枚举 \(r_y=y\) 维护 \(l_y \in [y',mid]\),所以倒着跑一遍就行了。
时间复杂度 \(O(NM\log M)\),但是由于 \(\min(N,M)\le \sqrt{NM}\),所以分治大小较小的那边可以做到 \(O(NM\log \sqrt{NM})\)。代码 \(to_{i,j}\) 就是 \(nxt_{i,j}\)。
il void work(int l,int r){
if(l>r) return ;
if(l==r){
for(re int i=1,j=0;i<=n;++i){
j=max(j,i-1);
while(j+1<=n&&a[j+1][l]) ++j;
int len=j-i+1;
if(len<=K) res+=len;
else res+=K;
}
return ;
}
int mid=l+r>>1;
work(l,mid),work(mid+1,r);
for(re int i=1;i<=n;++i){
Mi[mid]=inf;
for(re int j=mid+1;j<=r;++j) Mi[j]=min(Mi[j-1],to[j][i]),tt[j]=mid+1;
int mi=inf,R=mid;
for(re int L=mid;L>=l;--L){
mi=min(mi,to[L][i]);
while(R+1<=r&&Mi[R+1]>=mi){
++R;
tt[R]=L+1;
}
//[mid+1,R]
if(mid+1<=R) res+=c[R-L+1][mi]-c[mid-L+1][mi];
//[R+1,r]
}
++R;
for(;R<=r;++R) tt[R]=l;
for(re int j=mid+1;j<=r;++j)
if(tt[j]<=mid){
res+=c[j-tt[j]+1][Mi[j]]-c[j-(mid+1)+1][Mi[j]];
}
}
return ;
}
il int gg(){
char c;cin>>c;
return (c=='.');
}
il void solve(){
cin>>n>>m>>K;
for(re int i=1;i<=n;++i) a[i].reserve(m+5);
for(re int i=0;i<=m;++i) c[i].reserve(n+5),to[i].reserve(n+5);
for(re int i=1;i<=n;++i)
for(re int j=1;j<=m;++j) a[i][j]=gg();
//to[x][y] x 列 y 行
for(re int j=1;j<=m;++j){
int lst=n;
for(re int i=n;i>=1;--i){
if(a[i][j]) to[j][i]=lst-i+1;
else lst=i-1,to[j][i]=0;
}
}
for(re int i=1;i<=m;++i)
for(re int j=1;j<=n;++j) c[i][j]=c[i-1][j]+min(j,K/i);
work(1,m);
cout<<res;
return ;
}
AT_abc420_g sqrt(n²+n+X)
G<<<E 是什么意思。
记 \(\sqrt{n^2+n+X}=m\),两边平方一下有 \(n^2+n+X=m^2\)。
\(m^2-n^2-n=X\),等式因式分解下有 \((2m+(2n+1))(2m-(2n+1))=4X-1\)。然后右边是定值,枚举 \(4X-1\) 的因数找左边的整数解数量就行了。时间复杂度 \(O(\sqrt{X})\)。
CF2133C The Nether
先对每个 \(i\) 询问从 \(i\) 出发的最长路。那么就可以知道最长路的长度。对于一个最长路径 \(P_1,P_2,P_3,\dots,P_k\),显然满足从 \(P_{i}\) 出发的最长路比从 \(P_{i-1}\) 出发的最长路小 \(1\)。那么存下最长路为 \(x\) 的所有点,只需要看和最长路为 \(x+1\) 的点是否有连边即可。那么最坏情况下除了起点每个点都会被询问 \(2\) 次,所以是 \(2n-1\) 次询问。
CF2133D Chicken Jockey
定义状态函数 \(f_i\) 表示前 \(i\) 个怪死亡的最小代价。那么对于 \(i\) 来说,要么坠落 \(1\) 要么和 \(i-1\) 一起死。有 \(f_i=\min (f_{i-1}+h_{i}-1,f_{i-2}+h_{i-1}+\max(0,h_i-i))\)。
CF2133E I Yearned For The Mines
首先一个大小为 \(3\) 的联通块可以顺着过去询问,因为一条链我们从头开始往下询问时目标一定不会出现在已经被询问过的点中。那么对于大小大于 \(3\) 的情况,如果当且与 \(u\) 直接联通且在 \(u\) 为根的子树中的点的数量不小于 \(4\),那么我们对 \(u\) 进行一次操作 \(2\) 是不劣的。由于每 \(4\) 个点最多有 \(1\) 个点进行了操作 \(2\),那么最多有 \(\frac{n}{4}\) 个操作 \(2\)。满足条件。