! P6300悔改——平衡复杂度

学会平衡复杂度!!!

\(f_k=\sum_{i+j=k,i,j\in[1,m]}min(c_i,c_j)\)

\(ans=max(f_k)/2\)

这个式子挺像卷积,考虑如何卷积求min

枚举小于等于c的即可好难\(f_k=\sum_{u=1}^n\sum_{i+j=k}[c_i\ge u][c_j\ge u]\)

但这样复杂度\(O(nmlog_m)\)

考虑平衡复杂度

\(t\)\(u\leq t\)时卷积,否则暴力(只有\(min(m,n/t)\)个会大于\(t\)

时间复杂度\(O(tmlogm+\frac{n^2}{t^2})\)

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
#define ll long long
const int mod=998244353,g=3;
inline int ksm(int x,int r){
	int ret=1;
	for(int i=0;(1ll<<i)<=r;i++){
		if((r>>i)&1)ret=(ll)ret*x%mod;
		x=(ll)x*x%mod;
	}
	return ret;
}
const int N=1e5+4;
int rev[N<<2];
inline void NTT(int *a,int len,int lim,int fl){
	for(int i=0;i<len;i++){
		rev[i]=(rev[i>>1]>>1)|((i&1)<<lim-1);
		if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(int mid=1,tmp,x,u,v;mid<len;mid<<=1){
		tmp=ksm(g,(mod-1)/(mid<<1));
		if(fl==-1)tmp=ksm(tmp,mod-2);
		for(int i=0;i<len;i+=(mid<<1)){
			x=1;
			for(int j=0;j<mid;j++,x=(ll)x*tmp%mod){
				u=a[i+j];v=(ll)x*a[i+j+mid]%mod;
				a[i+j]=(u+v)%mod;a[i+j+mid]=(u-v+mod)%mod;
			}
		}
	}
	if(fl==-1)for(int i=0,tmp=ksm(len,mod-2);i<len;i++)
		a[i]=(ll)a[i]*tmp%mod;
}
int n,m,t,lim,len=1,ans,tot,a[N<<2],b[N],c[N],f[N<<1];
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)c[read()]++;
	t=sqrt(sqrt((ll)n*n/m));//数据分治 
	while(len<=(m<<1)){len<<=1;lim++;}
	for(int i=1;i<=t;i++){
		for(int j=1;j<=m;j++){
			if(c[j]>=i)a[j]=1;
			else a[j]=0;
		}
		a[0]=0;
		for(int j=m+1;j<len;j++)a[j]=0;
		NTT(a,len,lim,1);
		for(int j=0;j<len;j++)a[j]=(ll)a[j]*a[j]%mod;
		NTT(a,len,lim,-1);
		for(int j=1;j<=(m<<1);j++)f[j]+=a[j];
	}
	for(int i=1;i<=m;i++){
		c[i]-=t;
		if(c[i]>0){
			c[++tot]=c[i];
			b[tot]=i;
		}
	}
	for(int i=1;i<=tot;i++)
		for(int j=1;j<=tot;j++)
			f[b[i]+b[j]]+=min(c[i],c[j]);
	for(int i=1;i<=(m<<1);i++)
		if(f[i]>f[ans])ans=i;
	cout<<f[ans]/2<<" "<<ans;
	return (0-0);
}

猜你喜欢

转载自www.cnblogs.com/aurora2004/p/12650098.html
今日推荐