2020牛客多校第七场A-Social Distancing

Statement

在半径为 r r r的圆中塞进 n n n个人,使他们两两相距最远,求最远距离
CF原题

Solution

可以用玄学的模拟退火
正常一点,我们考虑 D P DP DP
n n n个点距离和为

∑ i = 1 n ∑ j = 1 n ( x i − x j ) 2 + ( y i − y j ) 2 \sum_{i=1}^n\sum_{j=1}^n(x_i-x_j)^2+(y_i-y_j)^2 i=1nj=1n(xixj)2+(yiyj)2

由于减法难维护,我们考虑化成加法

       ( a − b ) 2 = a 2 + b 2 − 2 a b \,\,\,\,\,\,(a-b)^2=a^2+b^2-2ab (ab)2=a2+b22ab

       ( a − b ) 2 + ( b − c ) 2 + ( a − c ) 2 \,\,\,\,\,\,(a-b)^2+(b-c)^2+(a-c)^2 (ab)2+(bc)2+(ac)2

= 2 ( a 2 + b 2 + c 2 ) − 2 a b − 2 b c − 2 a c =2(a^2+b^2+c^2)-2ab-2bc-2ac =2(a2+b2+c2)2ab2bc2ac

= 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

可以推出

       ∑ i = 1 n ∑ j = 1 n ( x i − x j ) 2 + ( y i − y j ) 2 \,\,\,\,\,\,\sum_{i=1}^n\sum_{j=1}^n(x_i-x_j)^2+(y_i-y_j)^2 i=1nj=1n(xixj)2+(yiyj)2

= n ∗ ∑ i = 1 n x i 2 + y i 2 − ( ∑ i = 1 n x i 2 + y i 2 ) 2 =n*\sum_{i=1}^nx_i^2+y_i^2-(\sum_{i=1}^nx_i^2+y_i^2)^2 =ni=1nxi2+yi2(i=1nxi2+yi2)2

前面一项可以直接算,后面一项是勾股定理
接下来就是搬砖 D P DP DP

Code

参考乐正绫大佬

#include <cstdio>
#include <vector>
#include <algorithm>
const int N=300,M=32;
using namespace std;
struct Infected{
    int x,y,dis;
    Infected(){}
    Infected(int _x,int _y,int _d){x=_x,y=_y,dis=_d;}
    bool friend operator<(Infected a,Infected b){return a.dis<b.dis;}
};
vector<Infected> vec;
int T,n,R,i,j,k,dp[10][N<<1][N<<1],ans[50][50];
int main(){
    for(i=-M;i<=M;++i)for(j=-M;j<=M;++j)vec.push_back(Infected(i,j,i*i+j*j));
    for(i=0;i<=8;++i)for(j=0;j<2*N;++j)for(k=0;k<2*N;++k)dp[i][j][k]=-2e9;
    sort(vec.begin(),vec.end());
    register int s=0;
    dp[0][N][N]=0;
    for(register int r=1;r<=30;++r){
        while(vec[s].dis<=r*r){
            for(i=1;i<=8;++i)for(j=N-r*i;j<=N+r*i;++j)for(k=N-r*i;k<=N+r*i;++k)
                dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-vec[s].x][k-vec[s].y]+vec[s].dis);
            ++s;
        }for(i=1;i<=8;++i)for(j=0;j<N*2;++j)for(k=0;k<N*2;++k)
            if(dp[i][j][k]>0)ans[i][r]=max(ans[i][r],i*dp[i][j][k]-(N-j)*(N-j)-(N-k)*(N-k));
    }scanf("%d",&T);while(T--)scanf("%d%d",&n,&R),printf("%d\n",ans[n][R]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值