题目链接:https://ac.nowcoder.com/acm/contest/877/I
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

在哈乐冰的中央大街上有N个仓买, 我们可以将其抽象为一条线段上有N个顶点,仓买在线段上是均匀分布的,也就是说1号仓买在顶点1这个位置,2号仓买在顶点2这个位置...N号仓买在N这个位置。刚开始这些仓买之间是互相不通的,为了交流,工程师们建了一些路,但是由于资金有限,并不能在两两之间建一条路,他们只能有选择的建一些路。如果两个仓买A,B满足A是B的倍数,则A,B之间可以通一条路,当然这些路是双向的,A可以到B,B可以到A
例如N=8的时候:
仓买1向所有其他仓买通一条路。
2号仓买向4,6,8号仓买通路。
3号仓买仅和6号仓买通路。
4号仓买仅和8号仓买通路。
众所周知,建路需要花费很大一笔钱,所以资本家们需要过路的人需要收取一定费用,如果仓买A,B之间通路,则过路费为元。
现在小M站在1号仓买上,他想得知他分别到达1,2,3...N号仓买的最小花费。虽然他可以直接从1号仓买到达其他仓买,但是可以通过中转的方式让花费更少。你能帮帮他吗?

输入描述

输入一个整数,表示共有N个仓买。

输出描述

一行,输出N个整数,以空格隔开,分别代表从1号仓买到其他仓买的最小花费。

输入

8

输出

0 1 4 5 16 13 36 21

说明

1号到1号仓买自身,不需花费,为0
1号到2号仓买,直接到达,花费
1号到3号仓买,直接到达,花费
1号到4号仓买,直接到达花费9。但是可以先到达2,再通过2到4的路到达,花费为
1号到5号仓买,直接到达,花费16
1号到6号仓买,1->3->6,花费13
1号到7号仓买,1->7,花费36
1号到8号仓买,通过1->2->4->8,花费为21

解题思路

题意:n个仓库,如果两个仓买A,B满足A是B的倍数,则A,B之间可以通一条路,当然这些路是双向的,A可以到B,B可以到A,如果仓买A,B之间通路,则过路费,从1号出发,求到每个仓库的最小花费。
题解:筛法,递推。

#include <bits/stdc++.h>
using namespace std;
long long dp[500005]; // dp[i]代表从1~i的最小花费
int main() {
    int n;
    scanf("%d", &n);
    memset(dp, 0x3f, sizeof(dp));
    dp[1] = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = i + i; j <= n; j += i)
            dp[j] = min(dp[j], dp[i] + 1ll * (j - i) * (j - i));
    }
    for (int i = 1; i <= n; i++)
        printf("%lld ", dp[i]);
    printf("\n");
    return 0;
}