異或差分序列 P3943 星空 區間異或差分

2021-10-13 04:50:56 字數 2926 閱讀 5635

\(\color\)

逃不掉的那一天還是來了,小 f 看著夜空發呆。

天上空蕩蕩的,沒有一顆星星——大概是因為天上吹不散的烏雲吧。

心裡吹不散的烏雲,就讓它在那裡吧,反正也沒有機會去改變什麼了。

小 c 拿來了一長串星型小燈泡,假裝是星星,遞給小 f,想讓小 f 開心一點。不過,有 著強迫症的小 f 發現,這串一共 n 個燈泡的燈泡串上有 k 個燈泡沒有被點亮。小 f 決定 和小 c 一起把這個燈泡串全部點亮。

不過,也許是因為過於笨拙,小 f 只能將其中連續一段的燈泡狀態給翻轉——點亮暗燈 泡,熄滅亮燈泡。經過摸索,小 f 發現他一共能夠翻轉 m 種長度的燈泡段中燈泡的狀態。

小 c 和小 f 最終花了很長很長很長很長很長很長的時間把所有燈泡給全部點亮了。他 們想知道他們是不是蠢了,因此他們找到了你,讓你幫忙算算:在最優的情況下,至少需要 幾次操作才能把整個燈泡串給點亮?

\(\color\)、

從標準輸入中讀入資料。

輸入第 1 行三個正整數 n,k,m。

輸入第 2 行 \(k\) 個正整數,第 i 個數表示第 i 個被沒點亮的燈泡的位置 \(a_i\)

輸入第 3 行 \(m\) 個正整數,第 i 個數表示第 i 種操作的長度 \(b_i\)

保證所有 \(b_i\) 互不相同;保證對於 \(1 \le i < k\),有 \(a_i< a_i+1\);保證輸入資料有解。

\(\color\)

輸出標準輸入中。

輸出一行乙個非負整數,表示最少操作次數。

\(\color\)

5 2 2

1 53 4

\(\color\)

\(\color\)

【樣例 1 解釋】

【資料範圍與約定】

子任務會給出部分測試資料的特點。如果你在解決題目中遇到了困難,可以嘗試只解 決一部分測試資料。

每個測試點的資料規模及特點如下表

特殊性質:保證答案小於 4

\(\color\)

每次區間異或,而且區間長度比較長,於是考慮差分,轉為兩個端點的異或

總共要翻轉k個燈, 因此差分序列長度最多為2k且一定是偶數個

每次可以消除兩個1,消除的代價與距離有關,現在問題轉為把所有1消去的最小代價

消除的代價可以用完全揹包來求,設\(v[i]\)為翻轉長度為i的區間的最小代價

把每個翻轉操作的長度當做兩個物品x和-x,乙個是影響作用\(0\to1\),乙個是抵消作用\(1\to0\)

這樣代價可以\(o(nm)\)的求出來

然後可以愉快的dp了,顯然要狀壓2k的1

直接設\(f[i]\)為i到達i狀態的最小代價,轉移的時候,列舉兩個1轉移即可

總複雜度\(o(nm+4^kk^2)\)

#include

#define ll long long

ll in() {

char ch; ll x = 0, f = 1;

while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);

for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));

return x * f;

const int maxn = 1e5 + 10;

int n, k, m, num;

int t[maxn], v[maxn], b[maxn], f[1002020];

void dfs(int zt) {

for(int i = 1; i <= num; i++) {

if(!(zt & (1 << (i - 1)))) continue;

for(int j = i + 1; j <= num; j++) {

if(!(zt & (1 << (j - 1)))) continue;

int now = zt ^ (1 << (i - 1)) ^ (1 << (j - 1));

if(f[now] > f[zt] + v[t[j] - t[i]]) {

f[now] = f[zt] + v[t[j] - t[i]];

dfs(now);

int main() {

// freopen("starlit.in", "r", stdin);

// freopen("starlit.out", "w", stdout);

n = in(), k = in(), m = in();

int x;

for(int i = 1, ls = -1; i <= k; i++) {

x = in();

if(x == ls + 1) t[num] = x + 1;

else t[++num] = x, t[++num] = x + 1;

ls = x;

memset(v, 0x3f, sizeof v);

v[0] = 0;

for(int i = 1; i <= m; i++) b[i] = in();

for(int i = 1; i <= m; i++)

for(int j = b[i]; j <= n; j++)

v[j] = std::min(v[j], v[j - b[i]] + 1);

for(int i = 1; i <= m; i++)

for(int j = n - b[i]; j >= 0; j--)

v[j] = std::min(v[j], v[j + b[i]] + 1);

memset(f, 0x3f, sizeof f);

f[(1 << num) - 1] = 0;

dfs((1 << num) - 1);

printf("%d", f[0]);

return 0;

標籤:0066ff,ch,點亮,color,燈泡,異或,差分,p3943,輸入

異或差分序列 P3943 星空 區間異或差分

color 逃不掉的那一天還是來了,小 f 看著夜空發呆。天上空蕩蕩的,沒有一顆星星 大概是因為天上吹不散的烏雲吧。心裡吹不散的烏雲,就讓它在那裡吧,反正也沒有機會去改變什麼了。小 c 拿來了一長串星型小燈泡,假裝是星星,遞給小 f,想讓小 f 開心一點。不過,有 著強迫症的小 f 發現,這串一共 ...

P3943 星空 區間異或差分

逃不掉的那一天還是來了,小 f 看著夜空發呆。天上空蕩蕩的,沒有一顆星星 大概是因為天上吹不散的烏雲吧。心裡吹不散的烏雲,就讓它在那裡吧,反正也沒有機會去改變什麼了。小 c 拿來了一長串星型小燈泡,假裝是星星,遞給小 f,想讓小 f 開心一點。不過,有 著強迫症的小 f 發現,這串一共 n 個燈泡的...

P3917 異或序列

p3917 異或序列 暴力字首異或列舉每乙個區間,再求和,60分。正解 按每一位來做 對於區間 l,r 如果它對答案有貢獻,區間中1的個數一定是奇數,可以按每一位取 1 1 include2 include3 include4 include5 include6 include7 include8 ...