题目描述
输入描述:
输出描述:
示例1
输入
2
4 2
5 10
输出
64
2496
题目大意
给定一个圆的半径 r r r,在圆上和圆内有 n n n个点,要求 ∑ i = 1 n − 1 ∑ j = i + 1 n d ( i , j ) 2 \mathop{\sum}\limits_{i=1}^{n-1}\mathop{\sum}\limits_{j=i+1}^{n}d(i,j)^2 i=1∑n−1j=i+1∑nd(i,j)2的最大值。其中 d ( i , j ) d(i,j) d(i,j)表示 i i i和 j j j之间的距离。即求所有点的距离的平方和的最大值。
分析
这题据说许多大佬是用模拟退火打表就AC了,蒟蒻终究是蒻了,模拟退火是什么都不知道(话说有大佬能在线给个答案吗?)。但是 乐 正 绫 乐正绫 乐正绫又是大佬,他提供了一种不用模拟退火的打表,而是用了神器动规,在此先%下了。(这个人是单人挑多校的)
首先我们先看看这些点是怎样取会使得答案最大。
上面给出了
n
n
n从二到六的最大的分布。我们可以发现,点总是分布在圆上比较大。
然后我们确定了点肯定都是在圆上而不是圆内。
接下来观察这个式子:
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
d
(
i
,
j
)
2
\mathop{\sum}\limits_{i=1}^{n-1}\mathop{\sum}\limits_{j=i+1}^{n}d(i,j)^2
i=1∑n−1j=i+1∑nd(i,j)2
其实为
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
(
x
i
−
x
j
)
2
+
(
y
i
−
y
j
)
2
\mathop{\sum}\limits_{i=1}^{n-1}\mathop{\sum}\limits_{j=i+1}^{n}(x_i-x_j)^2+(y_i-y_j)^2
i=1∑n−1j=i+1∑n(xi−xj)2+(yi−yj)2
其中
x
y
xy
xy为横纵坐标。
于是我们可以来推一推几个式子。
如果有
a
b
ab
ab两个数
则
(
a
−
b
)
2
=
a
2
+
b
2
−
2
a
b
(a-b)^2=a^2+b^2-2ab
(a−b)2=a2+b2−2ab
a
b
c
abc
abc
则
(
a
−
b
)
2
+
(
a
−
c
)
2
+
(
b
−
c
)
2
(a-b)^2+(a-c)^2+(b-c)^2
(a−b)2+(a−c)2+(b−c)2
=
2
(
a
2
+
b
2
+
c
2
)
−
2
a
b
−
2
a
c
−
2
b
c
=2(a^2+b^2+c^2)-2ab-2ac-2bc
=2(a2+b2+c2)−2ab−2ac−2bc
=
2
(
a
2
+
b
2
+
c
2
)
+
a
2
+
b
2
+
c
2
−
(
2
a
b
+
2
a
c
+
2
b
c
+
a
2
+
b
2
+
c
2
)
=2(a^2+b^2+c^2)+a^2+b^2+c^2-(2ab+2ac+2bc+a^2+b^2+c^2)
=2(a2+b2+c2)+a2+b2+c2−(2ab+2ac+2bc+a2+b2+c2)
=
3
(
a
2
+
b
2
+
c
2
)
−
(
a
+
b
+
c
)
2
=3(a^2+b^2+c^2)-(a+b+c)^2
=3(a2+b2+c2)−(a+b+c)2
…
\dots
…以此类推
那么对于
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
(
x
i
−
x
j
)
2
+
(
y
i
−
y
j
)
2
\mathop{\sum}\limits_{i=1}^{n-1}\mathop{\sum}\limits_{j=i+1}^{n}(x_i-x_j)^2+(y_i-y_j)^2
i=1∑n−1j=i+1∑n(xi−xj)2+(yi−yj)2
其中
s
i
g
m
a
sigma
sigma是可以转化的。可以变成
n
∗
∑
i
=
1
n
(
x
i
2
+
y
i
2
)
−
(
∑
i
=
1
n
x
i
)
2
−
(
∑
i
=
1
n
y
i
)
2
n*\mathop{\sum}\limits_{i=1}^{n}(x_i^2+y_i^2)-(\mathop{\sum}\limits_{i=1}^{n}x_i)^2-(\mathop{\sum}\limits_{i=1}^{n}y_i)^2
n∗i=1∑n(xi2+yi2)−(i=1∑nxi)2−(i=1∑nyi)2
然后可以用
d
p
dp
dp解了。
代码
#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30
using namespace std;
int dp[9][610][610],ans[50][50];
int main()
{
int t;
vector<pair<int,pair<int,int> > > cur;//禁止套娃
for(int i=-32;i<=32;i++)
for(int j=-32;j<=32;j++)
cur.push_back(make_pair(i*i+j*j,make_pair(i,j)));
int s=0;
sort(cur.begin(),cur.end());
for(int i=0;i<9;i++)
for(int j=0;j<600;j++)
for(int k=0;k<600;k++)
dp[i][j][k]=-2e9;
dp[0][300][300]=0;
for(int r=1;r<=30;r++){//半径
while(cur[s].first<=r*r){
for(int i=1;i<=8;i++)
for(int j=300-r*i;j<=300+r*i;j++)
for(int k=300-r*i;k<=300+r*i;k++)
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-cur[s].second.first][k-cur[s].second.second]+cur[s].first);
s++;
}
for(int n=1;n<=8;n++)
for(int h=0;h<600;h++)
for(int l=0;l<600;l++)
if(dp[n][h][l]>0)
ans[n][r]=max(ans[n][r],dp[n][h][l]*n-(h-300)*(h-300)-(l-300)*(l-300));
}//打表,慢不要慌,时限很长的
scanf("%d",&t);
while(t--){
int n,r;
scanf("%d%d",&n,&r);
printf("%d\n",ans[n][r]);
}
}
END
回想起来,乐正绫真的NB,单人怼得比多人六,%%%