同余最短路
[PA2024] Żelki
题目描述
共有 nnn 种糖豆,有 kkk 种颜色,第 iii 种糖豆颜色是 kik_iki,重量是 mim_imi,价格 cic_ici。现在要去购买糖豆,购买的糖豆需要包含所有 kkk 种颜色,且每种颜色购买的数量相同。
问对于在区间 [0,m−1][0,m-1][0,m−1] 的每个整数 rrr,满足购买的糖豆总重量对 mmm 取模为 rrr 的购买方案中最小花费是多少?如果不存在满足条件的购买方案,则输出 −1-1−1。
输入格式
第一行三个整数 n,kn,kn,k 和 m (1≤n,k,m≤7 000)m\ (1\le n,k,m\le 7\,000)m (1≤n,k,m≤7000),分别表示糖豆种类数,颜色数和参数。
接下来 nnn 行,每行三个整数 ki,mik_i,m_iki,mi 和 ci (1≤ki≤k,1≤mi≤m,1≤ci≤109)c_i\ (1\le k_i\le k,1\le m_i\le m,1\le c_i\le 10^9)ci (1≤ki≤k,1≤mi≤m,1≤ci≤109),分别表示第 iii 种糖豆的颜色,重量和价格。
输出格式
输出 mmm 行,第 iii 行表示满足购买的所有糖豆总重量对 mmm 取模为 i−1i-1i−1 的情况中花费的最小值。如果不存在这样的情况,输出 −1-1−1。
样例 #1
样例输入 #1
3 2 6
1 2 1
2 2 2
1 1 5
样例输出 #1
0
10
6
7
3
13
样例 #2
样例输入 #2
2 3 3
1 1 1
3 1 1
样例输出 #2
0
-1
-1
首先令 dpi,jdp_{i,j}dpi,j 表示用到第 iii 个颜色,体积对 mmm 取余为 jjj 的最小花费。
dp[i][(k+j.w)%m]=/min(dp[i][(k+j.w)%m],dp[i-1][k]+j.v) 。
然后就可以跑同余最短路了。
#include<bits/stdc++.h>
#define inf 1e18
using namespace std;
const int N=7010;
struct Node{
int w,v;
};
int n,k,m;
vector<Node> g[N];
long long dp[N][N],dis[N];
int gcd(int a,int b){
if(b) while((b%=a)&&(a%=b));
return a+b;
}
int main(){
scanf("%d%d%d",&n,&k,&m);
for(int i=1;i<=n;i++){
int ki,wi,ci;
scanf("%d%d%d",&ki,&wi,&ci);
g[ki].push_back((Node){wi,ci});
}
memset(dp,0x3f,sizeof(dp));
memset(dis,0x3f,sizeof(dis));
dp[0][0]=0;dis[0]=0;
for(int i=1;i<=k;i++){
for(auto j:g[i]){
for(int k=0;k<m;k++){
dp[i][(k+j.w)%m]=min(dp[i][(k+j.w)%m],dp[i-1][k]+j.v);
}
}
}
for(int i=1;i<m;i++){
int up=gcd(i,m);
for(int j=0;j<up;j++){
for(int t=j,c=0;c<2;c+=t==j){
dis[(t+i)%m]=min(dis[(t+i)%m],dis[t]+dp[k][i]);
t=(t+i)%m;
}
}
}
for(int i=0;i<m;i++){
if(dis[i]>=inf) printf("-1\n");
else printf("%llu\n",dis[i]);
}
return 0;
}

8870

被折叠的 条评论
为什么被折叠?



