1. 程式人生 > 其它 >P6187 [NOI Online #1 提高組] 最小環

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;
}