一些很妙的思維題

2022-05-06 21:57:13 字數 4768 閱讀 9865

有一張 \(n\) 個點 \(m\) 條邊的圖,點有點權,邊有邊權。

先手後手輪流染黑白兩色,最後的得分是自己染的點權和 + 兩端均為自己的顏色的邊權和。

雙方都希望自己的得分 - 對手的得分最大,求結果。

\(1 \le n \le 10000, 0 \le m \le 100000\)

這題巨妙無比,真是妙蛙種子吃著妙脆角,秒進了公尺奇妙妙屋,秒到家了。

你可以考慮把每一條邊都分到他所連的 \(2\) 個點上,各一半。

然後對於每條邊,我們有 \(2\) 種可能,如下:

#include #include #include using namespace std;

const int maxn = 10010;

int n, m, u, v, w;

double a[maxn];

double cmp(double x, double y)

int main()

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

sort(a + 1, a + n + 1, cmp);

double ans = 0;

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

else

}printf("%d", (int) ans);

return 0;

}

給你若干個區間 \([l_i, r_i]\) ,每次可以對乙個區間進行整體異或操作。

區間初始全 \(0\),問你最後可以形成多少種不同的區間。

考慮什麼樣的區間是沒有貢獻的。

假設對於區間 \([l, r]\) ,我們考慮如果存在以下三個區間,那麼這個區間是無用的。

那麼通過不同的組合,有無區間 \([l, r]\) 是沒有意義的。

那麼用並查集維護端點就行了。

#include using namespace std;

const int maxn = 100010;

const int xrz = 1e9 + 7;

const int maxm = (1 << 21);

int n, m, ans = 1, l, r, f[maxn];

int find(int x)

int main()

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

f[x] = y;

ans = (ans * 2) % xrz;

} printf("%d", ans);

return 0;

}

一共 \(n\) 天,每天上午會進 \(a_i\) 的物品,中午會有乙個客人想要買走 \(b_i\) 的物品,當然你也可以選擇不買,問你最後最多可以交易多少次。

資料範圍 : \(1 <= n <= 250000, 0 <= a_i, b_i <= 10^9\)

首先,我們看到題目先會想到 \(01\) 揹包。是個正確的作法,但是肯定過不了。

然後,我們考慮到這一定是個貪心/推式子的題目。

但是推式子的題目一般的特性在這裡顯然不符合(推式子的題目一般不會讓你選擇)

那接下來考慮怎麼去貪心。

第一想法是我們選最小的肯定是最優的,因為就算選了這個最小的而導致其他的不可以選,那也最多只能導致乙個不可以選。

因為如果可以導致多個不可以選的話,選了次小的哪乙個也會導致更多的不可以選。

所以選擇最小的策略是對的,\(sort\) 一般的複雜度我們也可以接受,但是問題來了,我們那些數可以取?

取完當前最小的,那麼它前面的一些數說不定不可以再去。

那麼處理這些的複雜度就不穩定了,可以構造資料卡掉。

接下來我們想每天上午進的貨物會對什麼有影響。

這個很顯然,它可以對他後面的所有數產生影響,因為到貨了就可以賣給別人了。

那是不是可以這麼考慮,從後往前去跑,每次去當前可以取的最小的。

因為從後完全就去除了它的後效性,所有正確性也是對的。

但是新增乙個數 \(a_i\) 可能很大,一次可以處理多個數。

那你就必須保證後面整個序列是有序的,而且還要維護乙個字尾和。

我們考慮維護這個有序數列的複雜度最優,那就是往前加乙個數,就把這個數加入到數列裡面去。

這樣的複雜度最劣是 \(o(n^2)\) 的,還是會炸。

那我們是不是無法從一些順序上去找到優化的空間。

我們就可以考慮去莽,然後支援撤銷,這樣也可以保證正確性。

具體的話是這樣實現的:

從前往後讀入,每次可以取就取,並且把這些取過的記錄在單調佇列中。

如果當前這個放不下,我們就把他和佇列首的元素做比較,不斷更新即可。

根據我們的第二個想法,每個前面取過的如果彈出來,因為他的後效性,肯定是可以服務後面的。

那麼就結束了。

#include using namespace std;

#define int long long

const int maxn = 250010;

int n, sum, ans, book[maxn];

priority_queue, vector> > q;

struct node e[maxn];

int cmp(node x, node y)

signed main()

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

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

else if(! q.empty() && q.top().first > e[i].b)

}printf("%lld\n", ans);

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

}return 0;

}

有 \(n\) 個小矮人,每個小矮人有身高 \(a_i\) 和 臂長 \(b_i\)

乙個小矮人可以出去的條件是

\[\sum_^ + b_k >= h

\]問最多可以跑出去多少小矮人。

因為人人平等對吧,所以每個人的價值都是一樣的。

那麼我們就考慮什麼樣的人更加容易出來。

是不是手長+臂長更長的人就更容易出來。

我們考慮有 \(2\) 個人 \(a\) 和 \(\text\) 。

並且 \(\text\) 可以單獨出來,\(\text\) 只可以在 \(a\) 的幫助下出來。

那麼肯定是要先把 \(b\) 放出來,再讓 \(a\) 後出來。

所以我們貪心的策略是把臂長+手長大的放後面。小的先跑出去。

至於我們怎麼實現跑出去的過程,跑一遍最簡單的 \(dp\) 就行了。

#include using namespace std;

const int maxn = 2010;

int n, h, sum, ans, f[maxn];

struct node e[maxn];

int cmp(node x, node y)

int main()

scanf("%d", &h);

sort(e + 1, e + 1 + n, cmp);

for(int i = 1; i <= n; ++ i) }}

for(int i = n; i >= 0; -- i)

}return 0;

}

給你乙個長度為 \(n\) 個字串,存在 \(3\) 種字元:

每個人的行走互不干擾,問你最少過多久才可以取完所有物品。

乍一看就感覺很 \(\text\) .

對每個人 \(\text\) ?

按時間 \(\text\) ?

感覺都不太對,那就不是 \(\text\) 了(大草)

我們考慮怎麼暴力去跑?

先列舉時間,再暴力的找每個人可以取的物品,這樣的複雜度是很恐怖的。

那麼我們先優化時間,對於時間 \(x\) 和 \(x + 1\),如果在 \(x\) 可以取完,那麼 \(x + 1\) 肯定也可以,所以時間是滿足單調性的,可以用二分優化到 \(\text\)

接下來考慮後面這個東西怎麼去 \(\text\) 。

對於每個人,他們可以取完的東西太多了,我們無法有效快速的求。

那我們就考慮對於每乙個物品去找哪個人可以收服他,這樣肯定只有 \(2\) 種決策,他左邊的第乙個人和他右邊的第乙個人。

預處理下就行了。

#includeusing namespace std;

#define mid ((l + r) >> 1)

const int maxn = 200010;

int n, nxt[maxn], ans, l[maxn], r[maxn], lst[maxn], now;

char s[maxn];

bool check(int x)

}for(int i = 1; i <= n; i ++)

if(nxt[i] && l[nxt[i]] < i)

if(nxt[i] == 0 || nxt[i] - i > x)

l[nxt[i]] = i;}}

return 1;

}int main()

else if(s[i] == '*')

}now = 0;

for(int i = n; i ; -- i)

else if(s[i] == '*')

}while(l <= r)

else

} printf("%d", ans);

return 0;

}

algorithm 一些有趣的思維題

hdu 1108 include iostream using namespace std intmain return0 乙個數的任何次方一共只有四種情況,分別列出這四種情況後取餘冪就可以知道尾數是多少。codeforces 1217a include iostream include algor...

資訊學競賽中的一些經典思維 題

倍增字面上意思是 成倍地增加。當模擬乙個過程時,一步一步進行太慢,考慮把模擬的步數二進位制分解 經過一些預處理,每次可以模擬 2 i 步,從而達到優化複雜度的目的。倍增主要模型有rmq,lca等。例題給出乙個長度為 n 的環和乙個常數 k,每次可以從第 i 個點跳到第 i k mod n 1 個點,...

js 的一些題

給出乙個區間 a,b 計算區間內 神奇數 的個數。神奇數的定義 存在不同位置的兩個數字,組成乙個兩位數 且不含前導0 且這個兩位數為質數。比如 153,可以使用數字3和數字1組成13,13是質數,滿足神奇數。同樣153可以找到31和53也為質數,只要找到乙個質數即滿足神奇數。輸入描述 輸入為兩個整數...