CF gym102354 B. Yet Another Convolution
题面传送门
看到gcd想到的应该是莫比乌斯反演。
但是这个取max而不是求和让这个莫反很难套上去。
有没有什么办法把这个max消掉呢?当然,我们可以二分,转化为计算大于等于这个值的数量。
变成这样的式子:\(\sum\limits_{i=1}^{\frac{n}{k}}{\sum\limits_{j=1}^{\frac{n}{k}}}{[\gcd(i,j)==1][|a_i-b_j|\geq mid]}\)
然后套路反演就可以得到\(\sum\limits_{d=1}^{\frac{n}{k}}{\mu_d \sum\limits_{i=1}^{\frac{n}{kd}}{\sum\limits_{j=1}^{\frac{n}{kd}}{[|a_i-b_j|\geq mid]}}}\)
后面那个东西显然可以排序以后双指针,然后你得到了一个时间复杂度高达\(O(n\log ^2n\log W)\)的好方法。
考虑优化,里面的瓶颈在于排序,容易发现里面只和\(kd\)而与\(k,d\)单独的值无关,所以可以在外围\(O(n\log^2 n)\)预处理出每个\(T=kd\)的排好序的vector,就可以降到\(O(n\log n(\log n+\log W))\)
另外如果\(\mu_i=0\)其实是不用算的,这样大概优化了\(\frac{1}{4}\)的时间。
code:
#include
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M (900+5)
#define K (200000+5)
#define mod 9248440332
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;vector C[N],D[N];
int n,mu[N],pr[N],ph,cnt,Len,Fl[N],A[N],B[N],l,r,mid;
I int CK(int mid,int id){
int i,j,R;ll Ans=0,ToT=0;for(i=id;i<=n;i+=id){
ToT=0;Len=D[i].size();R=0;for(j=0;j=C[i][j]+mid) R--;ToT+=Len-R-1;}Ans+=ToT*mu[i/id];
}return Ans;
}
int main(){
freopen("1.in","r",stdin);freopen("1.out","w",stdout);
int i,j;scanf("%d",&n);mu[1]=1;for(i=2;i<=n;i++){
!Fl[i]&&(mu[i]=-1,pr[++ph]=i);for(j=1;j<=ph&&i*pr[j]<=n;j++){Fl[i*pr[j]]=1;if(i%pr[j]==0) break;mu[i*pr[j]]=-mu[i];}
}for(i=1;i<=n;i++) scanf("%d",&A[i]);for(i=1;i<=n;i++) scanf("%d",&B[i]);
for(i=1;i<=n;sort(C[i].begin(),C[i].end()),sort(D[i].begin(),D[i].end()),i++)for(j=1;i*j<=n;j++) C[i].PB(A[i*j]),D[i].PB(B[i*j]);
for(i=1;i<=n;i++){cnt=0;l=0;r=1e9;while(l+1>1,(CK(mid,i)?l:r)=mid;printf("%d ",l);}
}