P12407 「CZOI-R3」数字变换 Solution
锐评一下难度,B 放困难推式子推半天不会做发现 CD 都是简单题,/tuu。再锐评一下出题人怎么不卡暴力枚举子集的
dp。定义状态
略微变形得到:
我们应当着手于后面的最小值。注意到这个值只和
会发现你枚举的
代码是 FMT 版本,和赛时写的暴力枚举子集相比总用时快了六倍。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 2e5 + 10;
const int V = 16;
int n, K, P, X[N], W[N][11];
namespace RAND {
int c, y[65536]; unsigned long long seed;
int get_rand(int mod)
{
seed ^= seed << 14;
seed ^= seed >> 7;
seed ^= seed << 19;
seed ^= seed << 23;
return seed % mod;
}
void get_input()
{
for (int i = 0; i < c; i ++) cin >> y[i];
for (int i = 1; i <= n; i++) X[i] = y[get_rand(c)];
for (int i = 1; i <= n; i++) for (int j = 1; j <= K; j++) W[i][j] = get_rand(1000000);
}
}
LL DP[11][N], tmp[1 << 16], g[1 << 16]; int popc[1 << 16];
int main() {
freopen(".in", "r", stdin); freopen(".out", "w", stdout);
ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> P >> K >> RAND::c >> RAND::seed; RAND::get_input();
int mx = 0;
for (int i = 1; i <= n; i ++) mx = max(mx, X[i]);
memset(DP, 0x3f, sizeof DP); DP[0][P] = 0;
for (int i = 1; i <= K; i ++) {
memset(tmp, 0x3f, sizeof tmp); memset(g, 0x3f, sizeof g);
for (int j = 1; j <= n; j ++) g[X[j]] = min(g[X[j]], DP[i - 1][j]);
for (int j = 0; j < V; j ++) for (int k = 0; k < (1 << V); k ++)
if ((k >> j) & 1) g[k ^ (1 << j)] = min(g[k ^ (1 << j)], g[k]);
for (int j = 0; j < (1 << V); j ++) g[j] -= 2 * j;
for (int j = 0; j < V; j ++) for (int k = 0; k < (1 << V); k ++)
if ((k >> j) & 1) g[k] = min(g[k], g[k ^ (1 << j)]);
for (int j = 1; j <= n; j ++) DP[i][j] = g[X[j]] + 2 * mx + W[j][i];
}
for (int i = 1; i <= n; i ++) cout << DP[K][i] << " \n"[i == n];
return 0;
}