2020牛客暑期多校训练营(第七场)A Social Distancing —— DP,贪心

51 篇文章 0 订阅

This way

题意:

二维平面上你要确定n个点的位置,使得他们到零点的距离不超过r,且在这里插入图片描述
要最大

题解:

有模拟退火的做法,,没看过,也不是很懂怎么样才能多源点往最优方向走。
这个式子转换一下:
→ ∑ i = 1 n − 1 ∑ j = i + 1 n ( x i − x j ) 2 + ( y i − y j ) 2 \rightarrow\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^{n}(x_i-x_j)^2+(y_i-y_j)^2 i=1n1j=i+1n(xixj)2+(yiyj)2
→ ∑ i = 1 n − 1 ∑ j = i + 1 n x i 2 + x j 2 + y i 2 + y j 2 − 2 x i x j − 2 y i y j \rightarrow\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^{n}x_i^2+x_j^2+y_i^2+y_j^2-2x_ix_j-2y_iy_j i=1n1j=i+1nxi2+xj2+yi2+yj22xixj2yiyj
那么我们需要手模一下这个式子,然后会发现,左边 x i 2 + x j 2 x_i^2+x_j^2 xi2+xj2这里,每个x都会出现n-1次,然后的话,我们这里多加一个 x i 2 x_i^2 xi2,然后后面 − 2 x i x j -2x_ix_j 2xixj这里给他一个 x i 2 x_i^2 xi2,于是后面就变成了一个多项式展开,然后式子就变成了这样:
→ ∑ i = 1 n ( x i 2 + y i 2 ) − ( ∑ i = 1 n x i ) 2 − ( ∑ i = 1 n y i ) 2 \rightarrow\sum\limits_{i=1}^{n}(x_i^2+y_i^2)-(\sum\limits_{i=1}^{n}x_i)^2-(\sum\limits_{i=1}^{n}y_i)^2 i=1n(xi2+yi2)(i=1nxi)2(i=1nyi)2
那么我们要维护 ∑ i = 1 n x i \sum\limits_{i=1}^{n}x_i i=1nxi ∑ i = 1 n y i \sum\limits_{i=1}^{n}y_i i=1nyi
dp[i][j][k]就表示已经有了i个点的时候,j表示x的累加,k表示y的累加, ∑ i = 1 n ( x i 2 + y i 2 ) \sum\limits_{i=1}^{n}(x_i^2+y_i^2) i=1n(xi2+yi2)的累加的答案。
可以打表,如果需要同时枚举x,y会T。
但是这里有一点:x和y要贪心的更大,那么知道了x,y就是r*r-x*x
那么DP非常的暴力

#include<bits/stdc++.h>
using namespace std;
const int N=305,M=10;
int dp[M][N*2][N*2],ans[M][N];
int main()
{
    memset(dp,-1,sizeof(dp));
    dp[0][N][N]=0;
    for(int r=1;r<=30;r++){
        for(int x=-r;x<=r;x++){
            int y=sqrt(r*r-x*x);
            for(int i=1;i<=8;i++)
                for(int j=N-r*i;j<=N+r*i;j++)
                    for(int k=N-r*i;k<=N+r*i;k++){
                        if(~dp[i-1][j-x][k-y])
                            dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-x][k-y]+x*x+y*y);
                        if(~dp[i-1][j-x][k+y])
                            dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-x][k+y]+x*x+y*y);
                    }

        }
        for(int i=1;i<=8;i++)
            for(int j=N-r*i;j<=N+r*i;j++)
                for(int k=N-r*i;k<=N+r*i;k++)
                    if(~dp[i][j][k])
                        ans[i][r]=max(ans[i][r],dp[i][j][k]*i-(j-N)*(j-N)-(k-N)*(k-N));
    }



    int t;
    scanf("%d",&t);
    while(t--){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",ans[x][y]);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值