讲道理这个应该是类似矩阵的东西,但是太大了也不现实,相对应的,倍增可以解决的就是类似这样的单路径移动?思想上类似状压dp,本质。。好像也是dp
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <stack>
#include <queue>
#include <string.h>
#include <string>
#include <iomanip>
#include <cstring>
#include <vector>
#include <functional>
#include <cmath>
#include <sstream>
#include <set>
using namespace std;
#define PI acos(-1.0)
typedef long long ll;
//typedef unsigned long long ull;
#define sp system("pause")
const int N = 100000 + 10;
const int M = 35;
const int mod = 1e9 + 7;
const int inf = 1e9 + 7;
int f[N][M]; //记录第N个点第2^M次是在哪个点上
ll sum[N][M]; //记录第N个点经过2^M次的之和
int mn[N][M]; //几率第N个点经过2^M次的路径中的最小值
int main()
{
int n;
ll k;
cin >> n >> k;
for (int i = 0; i < n; i++)scanf("%d", &f[i][0]); //当前位置
for (int i = 0; i < n; i++){
scanf("%d", &sum[i][0]); mn[i][0] = sum[i][0];
}
for (int j = 1; j < M; j++)
{
for (int i = 0; i < n; i++)
{
f[i][j] = f[f[i][j - 1]][j - 1]; // 第i个点2^j-1次之后的点 经过2^j-1次 就是第i点经过2^j次
sum[i][j] = sum[f[i][j - 1]][j - 1] + sum[i][j - 1]; //前面后后一段, 后面前一段
mn[i][j] = min(mn[i][j - 1], mn[f[i][j - 1]][j - 1]); //同上
}
}
ll ans;
for (int i = 0; i < n; i++)
{
int v = i, minn = inf;
ans = 0;
for (int j = M - 1; j >= 0; j--)
{
ll xx = 1; xx <<= j;
if (k&xx) //枚举当前次数
{
ans += sum[v][j];
minn = min(minn, mn[v][j]);
v = f[v][j]; //将当前点转移到f[v][j]
}
}
printf("%I64d %d\n", ans, minn);
}
//sp;
}