原题请看这里
如今,梦网王国正遭受着全国性的流行病。 幸运的是,宝宝社长正在与疾病控制中心 ( C D C ) (CDC) (CDC)进行有效合作,他们正在尽最大努力使一切都受到控制。宝宝社长宣布了一项社会隔离政策,以防止病毒传播。 作为 C D C CDC CDC的负责人,您需要研究以下问题:
有n个人需要观察,并且您已经在 2 2 2维平面上的 ( 0 , 0 ) (0,0) (0,0)中设置了监视器。 每个人都应保持在r到显示器的距离之内。 您还必须使它们尽可能远离彼此。 为了简化问题,您只能将它们分配给整数坐标。
请最大化 ∑ i = 1 n − 1 ∑ j = i + 1 n d ( i , j ) 2 \sum_ {i=1}^{n-1}\sum_{j = i + 1} ^ {n} d(i,j)^2 ∑i=1n−1∑j=i+1nd(i,j)2,
其中 d ( i , j ) d(i,j) d(i,j)表示第 i i i个人与第 j j j个人之间的欧几里得距离。
有多个测试用例。 输入的第一行包含一个整数 T ( 1 ≤ T ≤ 250 ) T(1 \leq T \leq 250) T(1≤T≤250),表示测试用例的数量。
对于每个测试用例,唯一的行包含两个整数 n , r ( 1 ≤ n ≤ 8 , 1 ≤ r ≤ 30 ) n,r(1 \leq n \leq 8,1 \leq r \leq 30) n,r(1≤n≤8,1≤r≤30)。
对于每个测试用例,请在一行中输出答案。
2
4 2
5 10
64
2496
动态规划。
首先我们可以想到n个点的距离和为:
∑ i = 1 n ∑ j = 1 n ( x i − x j ) 2 ( y i − y j ) 2 \sum^n_{i=1}\sum^n_{j=1}(x_i-x_j)^2(y_i-y_j)^2 ∑i=1n∑j=1n(xi−xj)2(yi−yj)2
由于这个式子中有减法,较难维护,所以我们考虑把他转化成加法的形式:
∑ i = 1 n ∑ j = 1 n ( x i − x j ) 2 ( y i − y j ) 2 = n ∗ ∑ i = 1 n x 2 + y 2 − ( ∑ i = 1 x n x i 2 + y i 2 ) 2 \sum^n_{i=1}\sum^n_{j=1}(x_i-x_j)^2(y_i-y_j)^2=n*\sum^n_{i=1}x^2+y^2-(\sum^n_{i=1x}x_i^2+y_i^2)^2 ∑i=1n∑j=1n(xi−xj)2(yi−yj)2=n∗∑i=1nx2+y2−(∑i=1xnxi2+yi2)2
前一项可以直接得到,后一项可以通过勾股定理求得,然后就可以 d p dp dp了
由于数据范围较小,也可以算出所有答案后打表查询来做。
( d p dp dp预处理+ O ( 1 ) O(1) O(1)查询)
#include
#define ll long long
using namespace std;
const int MAXN=300;
const int mx=32;
int dp[9][MAXN*2][MAXN*2],ans[MAXN][MAXN];
vector<pair<int,pair<int,int> > > vec;
void ycl()
{
int s=0;
for(int i=-mx;i<=mx;++i)
for(int j=-mx;j<=mx;++j)
vec.push_back(make_pair(i*i+j*j,make_pair(i,j)));
sort(vec.begin(),vec.end());
memset(dp,-0x3f*2,sizeof(dp));
dp[0][MAXN][MAXN]=0;
for(int r=1;r<=30;++r){
while(vec[s].first<=r*r){
for(int i=1;i<=8;++i)
for(int j=MAXN-r*i;j<=MAXN+r*i;++j)
for(int k=MAXN-r*i;k<=MAXN+r*i;++k)
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-vec[s].second.first][k-vec[s].second.second]+vec[s].first);
s++;
}
for(int n=1;n<=8;++n)
for(int h=0;h<2*MAXN;++h)
for(int l=0;l<2*MAXN;++l)
if(dp[n][h][l]>0)
ans[n][r]=max(ans[n][r],n*dp[n][h][l]-((h-MAXN)*(h-MAXN)+(l-MAXN)*(l-MAXN)));
}
}
int t,n,r;
int main(){
ycl();
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&r);
printf("%d\n",ans[n][r]);
}
}
打表,总时间复杂度 O ( 1 ) O(1) O(1)。
#include
#define ll long long
using namespace std;
int ans[50][50]={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},{0,4,16,36,64,100,144,196,256,324,400,484,576,676,784,900,1024,1156,1296,1444,1600,1764,1936,2116,2304,2500,2704,2916,3136,3364,3600},{0,8,32,76,130,224,312,416,554,722,896,1064,1248,1512,1746,2016,2264,2600,2888,3218,3584,3912,4344,4712,5138,5612,6062,6536,6984,7520,8084},{0,16,64,144,256,400,576,784,1024,1296,1600,1936,2304,2704,3136,3600,4096,4624,5184,5776,6400,7056,7744,8464,9216,10000,10816,11664,12544,13456,14400},{0,24,96,218,384,624,880,1188,1572,2014,2496,2984,3520,4224,4870,5616,6336,7224,8056,9008,9984,10942,12080,13144,14326,15624,16896,18184,19488,20968,22480},{0,36,144,324,576,900,1296,1764,2304,2916,3600,4356,5184,6084,7056,8100,9216,10404,11664,12996,14400,15876,17424,19044,20736,22500,24336,26244,28224,30276,32400},{0,48,192,432,768,1224,1740,2356,3102,3954,4896,5872,6960,8280,9564,11016,12456,14160,15816,17666,19584,21500,23688,25808,28122,30624,33120,35664,38266,41200,44076},{0,64,256,576,1024,1600,2304,3136,4096,5184,6400,7744,9216,10816,12544,14400,16384,18496,20736,23104,25600,28224,30976,33856,36864,40000,43264,46656,50176,53824,57600}};
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,r;
scanf("%d%d",&n,&r);
printf("%d\n",ans[n][r]);
}
}