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

Social Distancing

题目描述

在这里插入图片描述

输入描述:

在这里插入图片描述

输出描述:

在这里插入图片描述

示例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=1n1j=i+1nd(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=1n1j=i+1nd(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=1n1j=i+1n(xixj)2+(yiyj)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 (ab)2=a2+b22ab

a b c abc abc
( a − b ) 2 + ( a − c ) 2 + ( b − c ) 2 (a-b)^2+(a-c)^2+(b-c)^2 (ab)2+(ac)2+(bc)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)2ab2ac2bc
= 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=1n1j=i+1n(xixj)2+(yiyj)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 ni=1n(xi2+yi2)(i=1nxi)2(i=1nyi)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,单人怼得比多人六,%%%

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值