专栏文章
题解:B4373 [GXPC-S 2025] 队伍集结 / team
B4373题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mingwzw4
- 此快照首次捕获于
- 2025/12/02 02:13 3 个月前
- 此快照最后确认于
- 2025/12/02 02:13 3 个月前
看到数据范围,可以 求解,考虑动态规划。
那么使用动态规划四步法:
-
定义状态:定义 表示现在在第 个整数的位置时选择了一个汇合点,并且在第 个点之前已经选了 个点的最小答案。
-
确定答案: 的最小值。
-
状态转移方程:其中的 是 中大于 的整数值, 表示编号为 的不满值。
-
初始值与边界:
为所有点到 点的贡献和。
所以分析完了...吗?
这样看的话我们就需要枚举 ,时间高达 ,之后再枚举一个 显然会超时。
所以我们还需要优化,显然只有最后一个 进行优化最好。
那我们就可以令大于 的点的同学的编号为 到 。
后面的答案继续化简:
显然的,后面两个求和可以用后缀和维护。
所以代码如下:
CPP#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=5e2+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,k;
int dp[maxn][maxn];
int pos[maxn],ans=inf;
int sum[maxn],sum_x[maxn];
signed main(){
cin>>n>>k;
memset(dp,0x3f3f3f3f,sizeof(dp));
for(int i=0;i<=255;i++){
dp[i][1]=0;
}
for(int i=1;i<=n;i++){
int x,c;
cin>>x>>c;
pos[x]+=c;
for(int j=0;j<=255;j++){
dp[j][1]+=(x-j)*(x-j)*c;
}
}
for(int i=255;i>=0;i--){
sum[i]=sum[i+1]+pos[i];
sum_x[i]=sum_x[i+1]+pos[i]*i;
}
for(int i=0;i<=255;i++){
for(int j=0;j<i;j++){
for(int cnt=2;cnt<=k;cnt++){
int mid=(i+j)/2+1;
dp[i][cnt]=min(dp[i][cnt],dp[j][cnt-1]+2*(j-i)*sum_x[mid]+(i*i-j*j)*sum[mid]);
}
}
}
int ans=1e18;
for(int i=0;i<=255;i++){
ans=min(ans,dp[i][k]);
}
cout<<ans<<endl;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...