考慮狀壓 dp
\(f[mask]\) 表示當前已經排好序的顏色狀態為 \(mask\),最少的交換次數。
預處理移動的最小代價即可。
時間複雜度 \(\mathcal o(400\times 2^+20n\log n)\)
#include using namespace std;
const int n = 300005, m = 21;
int n;
vectorpos[m];
long long _move[m][m];
long long dp[1 << m];
int main()
for (int i = 1; i <= 20; ++i)
}} memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for (int mask = 0; mask < (1 << 20); ++mask)
}dp[mask | (1 << j)] = min(dp[mask | (1 << j)], dp[mask] + res); }}
} cout << dp[(1 << 20) - 1] << '\n';
return 0;
}
將兩個路徑拆成向上和向下的路徑,考慮樹上倍增維護答案
為了減少邊界的處理,令 \(prep_\) 表示從 \(i\) 的父親開始,向上倍增 \(j\) 次的答案
時間複雜度 \(\mathcal o(10\times n\log n)\)
#include using namespace std;
const int n = 1e5 + 1;
struct edge e[n << 1];
int head[n];
int edge_cnt;
void add_edge(int u, int v) ;
head[u] = edge_cnt;
}const int log = 17;
int n, m, q;
int bz[log + 1][n][11];
vectortag[n];
int father[log + 1][n];
int dep[n];
void dfs(int u, int father)
}int lca(int u, int v)
int c[11];
void merge(int* a, int* b)
for (int i = 0; i <= c[0]; ++i)
a[i] = c[i];
}void merge(int* a, vectorb)
for (int i = 0; i <= c[0]; ++i)
a[i] = c[i];
}void dfs_1(int u)
}void climb_up(int u, int v, int* ans)
}}int main()
dfs(1, 0);
for (int i = 1; i <= n; ++i)
tag[i].clear();
for (int i = 1; i <= m; ++i)
dfs_1(1);
for (int i = 1; i <= n; ++i)
for (int i = 1; i <= log; ++i)
for (int j = 1; j <= n; ++j)
int ans[11];
for (int qt = 1; qt <= q; ++qt) else if (v == _lca) else
cout << min(k, ans[0]) << ' ';
for (int i = 1; i <= min(k, ans[0]); ++i)
cout << ans[i] << ' ';
cout << '\n';
} return 0;
}
2020 08 08 省選B組 模擬 總結
估分 20 30 30 80 考場 0 50 60 110 奇奇怪怪的分數出現了。t1 由於沒有刪除輸出方案數的那一行,愉快爆零。考場瞎搞全排列,發現只與相對位置有關。於是嘗試 o n 4 dp 愉快炸裂。看來是我邊界以及方案數的統計打錯了。對於合併我們有多種可能,等等。係數係數!還有邊界邊界!好多...
NOIP提高組模擬賽3
周圍大佬都說初中打過n遍,我乙個菜雞瑟瑟發抖。把斐波那契數列寫出來找了半天性質,用了半個多小時推出來 x兔子的父親,就是x減去是在斐波那契數列中最大的小於x的數 舉個栗子 13號兔子,應減去8,得到他的祖先5 10號兔子,應減去8,得到他的祖先2 預處理出斐波那契數列,然後讓ab中較大的到他的祖先,...
NOIP提高組模擬賽4
丹青千秋釀,一醉解愁腸 無悔少年枉,只願壯志狂 矩陣字首和加暴力 o n 2m 2 60pts有手就行 觀察資料範圍,猜測應該是求一種 o n 3 的演算法,想到之前做的題,應該是 n 2 枚舉行,n 處理乙個序列的答案,然後,就沒有然後了 對於乙個序列,求子段和為k的倍數,如何 o n 求解,考慮...