2020暑期牛客多校训练营第七场(A)Social Distancing(平面几何,动态规划,打表)

Social Distancing

原题请看这里

题目描述:

如今,梦网王国正遭受着全国性的流行病。 幸运的是,宝宝社长正在与疾病控制中心 ( C D C ) (CDC) 进行有效合作,他们正在尽最大努力使一切都受到控制。宝宝社长宣布了一项社会隔离政策,以防止病毒传播。 作为 C D C CDC 的负责人,您需要研究以下问题:
有n个人需要观察,并且您已经在 2 2 维平面上的 ( 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
其中 d ( i j ) d(i,j) 表示第 i i 个人与第 j j 个人之间的欧几里得距离。

输入描述:

有多个测试用例。 输入的第一行包含一个整数 T ( 1 T 250 ) T(1 \leq T \leq 250) ,表示测试用例的数量。
对于每个测试用例,唯一的行包含两个整数 n r ( 1 n 8 , 1 r 30 ) n,r(1 \leq n \leq 8,1 \leq r \leq 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 = 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
前一项可以直接得到,后一项可以通过勾股定理求得,然后就可以 d p dp
由于数据范围较小,也可以算出所有答案后打表查询来做。

A C AC C o d e Code 1:

d p dp 预处理+ O ( 1 ) O(1) 查询)

#include<bits/stdc++.h>
#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]);
    }
}

A C AC C o d e Code 2:

打表,总时间复杂度 O ( 1 ) O(1)

#include<bits/stdc++.h>
#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]);
    }  
}

猜你喜欢

转载自blog.csdn.net/s260127ljy/article/details/107752828