同余最短路

同余最短路

[PA2024] Żelki

题目描述

共有 nnn 种糖豆,有 kkk 种颜色,第 iii 种糖豆颜色是 kik_iki,重量是 mim_imi,价格 cic_ici。现在要去购买糖豆,购买的糖豆需要包含所有 kkk 种颜色,且每种颜色购买的数量相同。

问对于在区间 [0,m−1][0,m-1][0,m1] 的每个整数 rrr,满足购买的糖豆总重量对 mmm 取模为 rrr 的购买方案中最小花费是多少?如果不存在满足条件的购买方案,则输出 −1-11

输入格式

第一行三个整数 n,kn,kn,km (1≤n,k,m≤7 000)m\ (1\le n,k,m\le 7\,000)m (1n,k,m7000),分别表示糖豆种类数,颜色数和参数。

接下来 nnn 行,每行三个整数 ki,mik_i,m_iki,mici (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 (1kik,1mim,1ci109),分别表示第 iii 种糖豆的颜色,重量和价格。

输出格式

输出 mmm 行,第 iii 行表示满足购买的所有糖豆总重量对 mmm 取模为 i−1i-1i1 的情况中花费的最小值。如果不存在这样的情况,输出 −1-11

样例 #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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值