P6187 [NOI Online #1 提高组] 最小环

题目大意

给定一个长度为 \(n\) 的正整数序列 \(a_i\)​,下标从 \(1\) 开始编号。我们将该序列视为一个首尾相邻的环,更具体地,对于下标为 \(i\), \((i \leqslant j)\) 的两个数 \(a_i\)​, \(a_j\)​,它们的距离为 \(\min(j-i, i+n-j)\)

现在再给定 \(m\) 个整数 \(k_1\)​, \(k_2\)​,..., \(k_m\)​,对每个 \(k_i​\)(\(i=1\), \(2\),..., \(m\)),你需要将上面的序列 \(a_i\)​ 重新排列,使得环上任意两个距离为 \(k_i\)​ 的数字的乘积之和最大。

思路

  1. 如果\(gcd(n,k_i)\ne 1\)则一定会形成多个部分

  2. \(k=1\)时,显然应该大的挨着大的,以最大的为中心,向两侧依次减少。

  3. \(k\ne 1\)\(gcd(n,k)\ne 1\)时,我们考虑将\(k=1\)时的代价断开,每一段长\(\frac{n}{k}\),一共有\(k\)段。

例如: 6 5 4 3 2 1
在k=1时为:6×5 6×4 5×3 4×2 3×1 1×2
在k=2时为:6×5 6×4 5×4 3×2 2×1 3×1

不难发现,若在i和i+1处断开,则对答案的贡献为
-(a[i]*a[i+2]+a[i-1]*a[i+1])+(a[i]*a[i-1]+a[i+1]*a[i+2])
  1. 预处理出来,然后乱搞即可

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<iomanip>

#define LL long long
#define N 200010
using namespace std;
LL n,m,a[N],ans[N];

LL read(){
	LL x=0,h=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+(LL)(ch-'0');ch=getchar();}
	return x*h;
}

LL gcd(LL a,LL b){
	return b==0 ? a:gcd(b,a%b);
}

void gans(LL k){
	LL jp=n/k;
	ans[k]=ans[1];
	for(LL i=n-jp;i;i-=jp){
		ans[k]-=(a[i+2]*a[i]+a[i-1]*a[i+1]);
		ans[k]+=(a[i]*a[i-1]+a[i+1]*a[i+2]);
	}
	return ;
}

void solve(){
	// solve q=0
	for(LL i=1;i<=n;i++){
		ans[0]+=(a[i]*a[i]);
	}
	
	// solve q=1
	ans[1]+=a[n]*a[n-1];
	for(LL i=n;i>2;i-=2){
		ans[1]+=a[i]*a[i-2];
	}
	for(LL i=n-1;i>2;i-=2){
		ans[1]+=a[i]*a[i-2];
	}
	ans[1]+=a[1]*a[2];
	
	// solve other
	for(LL i=2;i<=sqrt(n);i++){
		if(n%i!=0)continue;
		// solve i
		gans(i);
		// solve n/i
		if(n/i<=n/2)gans(n/i);
	}
}

int main(){
	n=read(); m=read();
	for(LL i=1;i<=n;i++)a[i]=read();
	sort(a+1,a+n+1);
	
	solve();
	for(LL i=1;i<=m;i++){
		LL x=read();
                //注意特判!!!
		if(n==1){
			printf("%lld\n",a[1]*a[1]);
			continue;
		}
		if(x==0)printf("%lld\n",ans[0]);
		else printf("%lld\n",ans[gcd(x,n)]);
	}
	return 0;
}

posted @ 2022-03-03 18:35  Charisk_FOD  阅读(69)  评论(0)    收藏  举报