【题解】CF1098E Fedya the Potter

Sol

先考虑那个 \(\gcd\) 操作。
显然可以枚举右端点维护。一个右端点对应的 \(\gcd\) 只有 \(\log\) 种。
那么就可以在 \(n \log^2 a_i\) 内处理出 \(cnt\) 数组。其中,\(cnt_i\) 表示 \(b\) 中有 \(cnt_i\)\(i\)
考虑二分答案,二分 \(mid\)
那么问题就变成了求 \(c\) 中比 \(mid\) 小的数的数量,也就是 \(b\) 中有几个区间的和小于 \(mid\)
显然,对于 \(b_l=b_r\) 的区间可以直接计算。考虑 \(b_l \lt b_r\)
首先一个区间必须满足 \(sum(l,r)=\sum_{b_l \lt b_i \lt b_r} b_i \lt mid\) 才有贡献。
如果 \(\sum_{l \leq i \leq r} cnt_i \lt mid\) 那么可以直接加上 \(cnt_l \times cnt_r\)。这种区间数量有很多,可以枚举 \(l\) 然后双指针求出 \(r\) 的区间。
否则这个区间一定满足 \(\left[l-1,r \right]\)\(\left[l,r-1 \right]\) 没有贡献,因此数量是 \(O(n)\) 级别的。双指针过程中也可以顺带求出这些区间。
把这些区间的贡献写出来:

\[\sum_{i=1}^{cnt_l} \sum_{j=1}^{cnt_r} \left[li+sum(i,j)+rj \lt mid \right] \]

用字母代替常量得

\[\sum_{i=0}^{A} \sum_{j=0}^{B} \left[ai+bj \leq c \right] \]

\(s=\min(A,\lfloor \frac{c}{a} \rfloor)\)\(t=\min(B,\lfloor \frac{c}{b} \rfloor)\),则

\[\begin{align} \notag & \sum_{i=0}^{A} \sum_{j=0}^{B} \left[ai+bj \leq c \right] \\ \notag =& \sum_{i=0}^{s} \sum_{j=0}^{t} \left[a(s-i)+bj\le c\right]\\ \notag =& (s+1)(t+1) - \sum_{i=0}^{s} \sum_{j=0}^{t} \left[ai+bj\le as+bt-c-1\right] \\ \notag =& (s+1)(t+1) - \sum_{i=0}^{\infty} \sum_{j=0}^{\infty} \left[ai+bj\le as+bt-c-1\right] \end{align} \]

对于后面那一坨,记 \(n=\lfloor \frac{c}{a} \rfloor\),则

\[\begin{align} \notag & \sum_{i=0}^{\infty} \sum_{j=0}^{\infty} \left[ai+bj \leq c \right] \\ \notag =& \sum_{i=0}^{n} \sum_{j=0}^{\infty} \left[a(n-i)+bj\leq c\right]\\ \notag =& \sum_{i=0}^{n} \sum_{j=0}^{\infty} \left[j+1 \leq \frac{ai+c-an+b}{b}\right]\\ \notag =& f(n,a,c-an+b,b) \end{align} \]

类欧即可。

Code

//LYC_music yyds!
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0)
#define lowbit(x) (x&(-x))
#define int long long
using namespace std;
inline char gc()
{
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
int read()
{
	int pos=1,num=0;
	char ch=getchar();
	while (!isdigit(ch))
	{
		if (ch=='-') pos=-1;
		ch=getchar();
	}
	while (isdigit(ch))
	{
		num=num*10+(int)(ch-'0');
		ch=getchar();
	}
	return pos*num;
}
void write(int x)
{
	if (x<0)
	{
		putchar('-');
		write(-x);
		return;
	}
	if (x>=10) write(x/10);
	putchar(x%10+'0');
}
void writesp(int x)
{
	write(x);
	putchar(' ');
}
void writeln(int x)
{
	write(x);
	putchar('\n');
}
const int N=1e6+10;
int sum[N],cnt[N],v[N],w[N],a[N],b[N],n,t,c[N],x,y,ans,now;
int f(int a,int b,int c,int n)
{
	int ac=a/c,bc=b/c,m=(a*n+b)/c,n1=n+1,n21=n*2+1,res=0;
	if (!a) return bc*n1;
	else if (a>=c||b>=c)
	{
		res=n*n1/2*ac+bc*n1;
		int now=f(a%c,b%c,c,n);
		res+=now;
		return res;
	}
	int now=f(c,c-b-1,a,m-1);
	res=n*m-now;
	return res;
}
int calc(int A,int B,int a,int b,int c)
{
//	cout<<A<<' '<<B<<' '<<a<<' '<<b<<' '<<c<<endl;
	if (A<0||B<0||c<0) return 0;
	int s=min(A,c/a),t=min(B,c/b),p=a*s+b*t-c-1,r=(s+1)*(t+1);
	if (p<0) return r;
	int n=p/a;
	return r-f(a,p-a*n+b,b,n);
}
int calc(int n,int m)
{
	return m*(2*n-m+1)/2;
}
bool check(int x)
{
	int res=0,j=0;
	for (int i=1;i<=100000;i++)
		if (c[i])
		{
			res+=calc(c[i],min(c[i],(x-1)/i));
			if (i<j) res+=c[i]*(cnt[j-1]-cnt[i])+calc(c[i]-1,c[j]-1,i,j,x-(sum[j-1]-sum[i])-i-j-1);
			while (j<=100000&&sum[j]-sum[i]<x)
				if (i<++j) res+=calc(c[i]-1,c[j]-1,i,j,x-(sum[j-1]-sum[i])-i-j-1);
		}
	return res<now;
}
int val(int x)
{
	return x*(x+1)/2;
}
signed main()
{
	n=read();
	for (int i=1;i<=n;i++)
	{
		int g=0,top=0,last=i+1;
		a[++t]=read(); b[t]=i;
		for (int j=t;j;j--)
		{
			if (!g||a[j]%g) v[++top]=g=__gcd(g,a[j]);
			c[g]+=last-b[j]; last=w[top]=b[j];
		}
		for (t=0;top;) b[++t]=w[top],a[t]=v[top--];
	}
	for (int i=1;i<=100000;i++)
		sum[i]=x+=c[i]*i,cnt[i]=y+=c[i];
	now=(val(val(n))+1)/2;
	int l=1,r=sum[100000];
	while (l<=r)
	{
		int mid=(l+r)>>1;
		if (check(mid)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	writeln(ans);
}





posted @ 2022-02-17 17:59  dd_d  阅读(90)  评论(2)    收藏  举报