2020牛客暑期多校训练营(第七场)A-Social Distancing dp打表

A- Social Distancing

题意

你要在半径为\(r\),圆心为\((0,0)\)的圆上找\(n\)个整数点,使得每对点的距离平方和最小。

\[\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}d(i,j)^2 \]

分析

考虑\(dp\)打表,状态\(dp[i][j][k]\)为放置了\(i\)个点,横坐标和为\(j\),纵坐标和为\(k\)的每个点和圆心的距离的平方和的最大值,为什么这样\(dp\)

把题目中的公式化简一下

\[\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}(x_i-x_j)^2+(y_i-y_j)^2 \\ =\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}x_i^2+x_j^2+y_i^2+y_j^2-2x_ix_j-2y_iy_j \\ =(\sum_{i=1}^{n}n(x_i^2+y_i^2))-(\sum_{i=1}^{n}x_i)^2-(\sum_{i=1}^{n}y_i)^2 \\ =n\times dp[n][j][k]-j^2-k^2 \]

维护第一项的值,枚举\(j,k\)去更新\(dp\)值,用数组\(ans[i][r]\)来更新在半径为\(r\)的圆,放置了\(i\)个点的答案,\(ans[i][r]=max \{i\times dp[i][j][k]-j^2-k^2 \}\)

打表Code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<sstream>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=1e5+10;
const int inf=1e9;
const int base=303;
int dp[11][610][610];
int ans[11][33];
vector<pii>q;
int main(){
	//ios::sync_with_stdio(false);
	//freopen("in","r",stdin);
	rep(i,-30,30){
		rep(j,-30,30){
			if(i*i+j*j<=30*30){
				q.pb(mp(i,j));
			}
		}
	}
	sort(q.begin(), q.end(),[](pii x,pii y){return x.fi*x.fi+x.se*x.se<y.fi*y.fi+y.se*y.se;});
	memset(dp,-1,sizeof(dp));
	dp[0][base][base]=0;
	int now=0;
	for(int r=1;r<=30;r++){
		for(;now<sz(q);++now){
			pii x=q[now];
			if(x.fi*x.fi+x.se*x.se>r*r) break;
			for(int i=1;i<=8;i++){
				for(int j=base-r*i;j<=base+r*i;j++) {
					for(int k=base-r*i;k<=base+r*i;k++) if(~dp[i-1][j-x.fi][k-x.se]){
						dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-x.fi][k-x.se]+(x.fi*x.fi+x.se*x.se));
					}
				}
			}
		}
		rep(i,1,8) rep(j,base-r*i,base+r*i) rep(k,base-r*i,base+r*i) if(~dp[i][j][k]){
			int t1=j-base,t2=k-base;
			ans[i][r]=max(ans[i][r],i*dp[i][j][k]-t1*t1-t2*t2);
		}
	}
	rep(i,1,8) rep(j,1,30){
		cout<<ans[i][j]<<',';
		if(j==30) cout<<'\n';
	}
	return 0;
}

Code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<sstream>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=1e5+10;
const int inf=1e9;
int T,n,r;
int a[8][30]={
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,
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,
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,
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,
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,
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,
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(){
    //ios::sync_with_stdio(false);
    //freopen("in","r",stdin);
    cin>>T;
    while(T--){
        cin>>n>>r;
        cout<<a[n-1][r-1]<<endl;
    }
    return 0;
}
posted @ 2020-08-02 14:45  xyq0220  阅读(356)  评论(0编辑  收藏  举报