#ST表#CF1879F Last Man Standing

发布时间 2023-10-28 00:17:48作者: lemondinosaur

洛谷题面
CF1879F


分析

\(x\) 大于最大值时一定可以被约化为等于的情况,考虑枚举 \(x\)

通过枚举倍数的方式可以知道存在若干段区间消耗同一精神状态的次数是相同的,那么区别就是其精神状态的差值。

那么可以用ST表维护精神状态次数的最大值和次大值,然后枚举倍数求出对于单个 \(x\) 的次数最大值次大值相减以求得最大值。


代码

#include <cstdio>
#include <cctype>
using namespace std;
const int N=200011; long long ans[N];
int lg[N],two[18],n,mx,h[N],a[N],f[N][18],g[N][18];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(long long ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
int main(){
	lg[0]=-1,two[0]=1;
	for (int i=1;i<N;++i) lg[i]=lg[i>>1]+1;
	for (int i=1;i<=lg[N-1];++i) two[i]=two[i-1]<<1;
	for (int T=iut();T;--T){
		n=iut(),mx=0;
		for (int i=1;i<=n;++i) h[i]=iut();
		for (int i=1;i<=n;++i){
			a[i]=iut();
			if (mx<a[i]) mx=a[i];
		}
		for (int i=1;i<=n;++i)
		if (h[f[a[i]][0]]<h[i]) g[a[i]][0]=f[a[i]][0],f[a[i]][0]=i;
		    else if (h[g[a[i]][0]]<h[i]) g[a[i]][0]=i;
		for (int j=1;j<=lg[mx];++j)
		for (int i=1;i+two[j]-1<=mx;++i){
			f[i][j]=f[i+two[j-1]][j-1],g[i][j]=g[i+two[j-1]][j-1];
			if (h[f[i][j]]<h[f[i][j-1]]) g[i][j]=f[i][j],f[i][j]=f[i][j-1];
			    else if (h[g[i][j]]<h[f[i][j-1]]) g[i][j]=f[i][j-1];
			if (h[g[i][j]]<h[g[i][j-1]]) g[i][j]=g[i][j-1];
		}
		for (int i=1;i<=mx;++i){
			int fi=0,se=0;
		    for (int j=1;j<=mx;j+=i){
			    int l=j,r=j+i>mx?mx:j+i-1,z=lg[r-l+1];
				int Fi=f[r-two[z]+1][z],Se=g[r-two[z]+1][z];
				if (h[Fi]<h[f[l][z]]) Se=Fi,Fi=f[l][z];
				    else if (Fi!=f[l][z]&&h[Se]<h[f[l][z]]) Se=f[l][z];
				if (h[Se]<h[g[l][z]]) Se=g[l][z];
				if ((a[fi]+i-1ll)/i*h[fi]<(a[Fi]+i-1ll)/i*h[Fi]) se=fi,fi=Fi;
				    else if ((a[se]+i-1ll)/i*h[se]<(a[Fi]+i-1ll)/i*h[Fi]) se=Fi;
				if ((a[se]+i-1ll)/i*h[se]<(a[Se]+i-1ll)/i*h[Se]) se=Se;
			}
			long long _fi=(a[fi]+i-1ll)/i*h[fi],_se=(a[se]+i-1ll)/i*h[se];
			if (ans[fi]<_fi-_se) ans[fi]=_fi-_se;
		}
		for (int i=1;i<=n;++i) print(ans[i]),putchar(i==n?10:32);
		for (int i=0;i<=n;++i) ans[i]=0;
		for (int i=1;i<=mx;++i) f[i][0]=g[i][0]=0;
	}
	return 0;
}