【题解】CF1098E Fedya the Potter

Sol

先考虑那个 gcd 操作。
显然可以枚举右端点维护。一个右端点对应的 gcd 只有 log 种。
那么就可以在 nlog2ai 内处理出 cnt 数组。其中,cnti 表示 b 中有 cntii
考虑二分答案,二分 mid
那么问题就变成了求 c 中比 mid 小的数的数量,也就是 b 中有几个区间的和小于 mid
显然,对于 bl=br 的区间可以直接计算。考虑 bl<br
首先一个区间必须满足 sum(l,r)=bl<bi<brbi<mid 才有贡献。
如果 lircnti<mid 那么可以直接加上 cntl×cntr。这种区间数量有很多,可以枚举 l 然后双指针求出 r 的区间。
否则这个区间一定满足 [l1,r][l,r1] 没有贡献,因此数量是 O(n) 级别的。双指针过程中也可以顺带求出这些区间。
把这些区间的贡献写出来:

i=1cntlj=1cntr[li+sum(i,j)+rj<mid]

用字母代替常量得

i=0Aj=0B[ai+bjc]

s=min(A,ca)t=min(B,cb),则

i=0Aj=0B[ai+bjc]=i=0sj=0t[a(si)+bjc]=(s+1)(t+1)i=0sj=0t[ai+bjas+btc1]=(s+1)(t+1)i=0j=0[ai+bjas+btc1]

对于后面那一坨,记 n=ca,则

i=0j=0[ai+bjc]=i=0nj=0[a(ni)+bjc]=i=0nj=0[j+1ai+can+bb]=f(n,a,can+b,b)

类欧即可。

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 @   dd_d  阅读(81)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示
主题色彩