【题解】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);
}

浙公网安备 33010602011771号