6482. 【GDOI2020模拟02.22】代数几何(algebraic)

题目描述


题解

怒草题解

类似burnside,可以得出循环节个数为gcd(n,k)

把每个循环节拉出来变成一个环,答案即为每个环的相邻元素乘积和

对于每个环首先把最大的放在中间,然后左右轮流从大到小放

可以感受到一个数大于另一个数时两边的数之和必然大于另一个数的和

所以不能交换,即为最优

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;

int n,i,j,k,l,T,K,N,len;
ll ans,a[5001];

bool cmp(int a,int b) {return a>b;}

int gcd(int x,int y)
{
	int r=x%y;
	
	while (r)
	x=y,y=r,r=x%y;
	
	return y;
}

int main()
{
	freopen("algebraic.in","r",stdin);
	#ifdef file
	freopen("algebraic.out","w",stdout);
	#endif
	
	scanf("%d",&n);
	fo(i,1,n)
	scanf("%lld",&a[i]);
	
	sort(a+1,a+n+1,cmp);
	
	scanf("%d",&T);
	for (;T;--T)
	{
		scanf("%d",&K);
		ans=0;
		
		if (!K)
		{
			fo(i,1,n)
			ans+=a[i]*a[i];
			
			printf("%lld\n",ans);
			continue;
		}
		
		N=gcd(n,K);
		len=n/N;
		
		for (l=0; l<n; l+=len)
		{
			ans+=a[l+1]*a[l+2]+a[l+len-1]*a[l+len];
			fo(i,1,len-2)
			ans+=a[l+i]*a[l+i+2];
		}
		
		printf("%lld\n",ans);
	}
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}
posted @ 2020-02-23 18:53  gmh77  阅读(263)  评论(0编辑  收藏  举报