題目大意爲:一個學生公寓中有多個房間,每一個房間有門牌號。已知一樓有且僅有兩個房間,其門牌號分別爲 1 和 2。給定數字 \(x\) ,以後每層樓中有 \(x\) 間房間。問:給你門牌號 \(n\) 和數字 \(x\) 。給出所在樓層。c++
1 <= n, x <= 1000
數組
*800
ide
很是簡單,分狀況討論:this
void solve(){ int n = read(), x = read(); if (n <= 2) cout << 1 << '\n'; else cout << (n - 2 + x - 1) / x + 1 << '\n'; }
用 \(n\) 個 \(2 \times 2\) 的正方形嘗試拼接出一個 \(m\times m\) 的關於主對角線對稱矩陣。spa
若是能夠輸出:
YES
不然輸出:NO
code
*900
blog
題目看起來有點麻煩,閱讀起來也比較長,實際上仔細一想,只要邊長能 mod 2,則咱們運用貪心的思路考慮問題,只須要一個 \(2\times 2\) 的主對角線對稱矩陣便可。繼承
主要的思路方向是大小類比,轉大爲小。遊戲
void solve(){ int n = read(), m = read(); int have = 0; for (int i = 0; i < n; ++ i){ int ul = read(), ur = read(); int dl = read(), dr = read(); if (dl == ur) have = 1; } if (m % 2 != 0 || have == 0) wprint("NO"); else wprint("YES"); }
給你一個數組 \(a\) ,最開始只包含一個數字 \(1\) 。你能夠作以下兩種操做:ci
- 給 \(a\) 中的某一元素加一
- 複製 \(a\) 中某一元素到數組末尾
回答,須要最少操做多少步,能使數組 \(a\) 中的總和大於 \(n\)。
1 <= n <= 1e9
*1100
通過思考,顯然倍增的效率是大於自增的,因而咱們能夠初步得出結論,咱們須要先自增而後再倍增。
設咱們自增到 \(k\) 再進行倍增。則須要的步驟數爲:
處理一下變爲:
由基本不等式可得:當 \(k = \sqrt{n}\) 時存在最小值,又由於這裏皆爲整數,經過計算機驗證以後獲得以下結論:
能夠記住如上結論。
void solve(){ int n = read(); int ans(0); int x = sqrt(n); ans = (n + x - 1) / x + x - 2; cout << ans << '\n'; }
給定一個長度爲 \(n\) 且不含 \(0\) 的序列 \(a\),能夠插入任何數字(能夠爲 \(\infty\) )。請問最少插入多少個數字才能保證序列中任意連續子序列和不爲 \(0\) 。
2 <= n <= 200000
-1e9 <= ai <= 1e9
*1500
這題關鍵點在於 快速肯定區間和爲 0 的狀況。
由於作過相似的,因此能夠很快的寫出來:即用 hashmap
。
接下來複制我在CF回覆別人的部分:
Let us define \(presum_{k}\) as the prefix sum, \(a_k\) as the array.
Let's define \(i,j\) as indexs(\(i < j\)):
In order to avoid this situation, we insert a \(+\infty\) behind the \(a_j\). Like this: \(a_{i+1}, \cdots, a_{j-1}, \stackrel{\infty}{\downarrow},a_{j}\).Then reconsider from \(a_j\)
void solve(){ int n = read(); unordered_map<LL, int> mp; // 0 --> not in, 1 --> in mp.clear(); LL sum(0), ans(0); for (int i = 0; i < n; ++ i){ int f = read(); sum += f; if (sum == 0 || mp.count(sum)) { ++ ans; mp.clear(); // Simulate inserting an infinite number sum = f; mp[sum] = 1; } else mp[sum] = 1; } cout << ans << '\n'; }
Alice和Bob進行剪刀石頭布的遊戲,總共進行\(n\)局。
Alice出石頭\(a_1\)次,出剪刀\(a_2\)次,出布\(a_3\)次。
Bob出石頭\(b_1\)次,出剪刀\(b_2\)次,出布\(b_3\)次。
問Alice最多贏多少次,最少贏多少次。
*1800
最大值很是簡單,咱們但願儘量能贏
實際上這題應該有更加數學的思路,可是考慮到整個問題空間的大小,所以能夠經過暴力搜索直接解決。
面對樣本空間很小的題目,咱們能夠優先計算窮舉的複雜度,快速解決。
時間複雜度大體爲 \(\mathcal{O}(2\cdot 3!)\)
int a[5], b[5]; int mn; void dfs(int ca, int cb, vector<int> visa, vector<int> visb, int cnt, vector<int> fa, vector<int> fb){ visa[ca] = visb[cb] = 1; if (fa[ca] >= fb[cb]){ if ((ca + 1) % 3 == cb) cnt += fb[cb]; fa[ca] -= fb[cb]; int ok =0; for (int i = 0; i < 3; ++ i){ if (visb[i] == 0) { // 誰沒有了,就在他可選的中間挑選一個 dfs(ca, i, visa, visb, cnt, fa, fb); ok = 1; } } if (ok == 0){ // 沒有什麼能夠選的了,說明結束了 mn = min(mn, cnt); return; } } else { if ((ca + 1) % 3 == cb) cnt += fb[cb]; fb[cb] -= fa[ca]; int ok = 0; for (int i = 0; i < 3; ++ i){ if (visa[i] == 0) { dfs(i, cb, visa, visb, cnt, fa, fb); ok = 1; } } if (ok == 0){ mn = min(mn, cnt); return; } } } void solve(){ int n = read(); for (int i = 0; i < 3; ++ i) a[i] = read(); for (int i = 0; i < 3; ++ i) b[i] = read(); int mx(0); for (int i = 0; i < 3; ++ i) mx += min(a[i], b[(i + 1) % 3]); VI visa(3, 0), visb(3,0); // visa --> a是否訪問, visb --> b是否訪問 VI fa(3, 0), fb(3, 0); // fa --> a 的各個數個數, fb --> 同 a mn = inf; for (int i = 0; i < 3; ++ i) fa[i] = a[i], fb[i] = b[i]; for (int i = 0; i < 3; ++ i){ // 枚舉各類狀況 for (int j = 0; j < 3; ++ j) dfs(i, j, visa, visb, 0, fa, fb); } wprint(mn, mx); }
給定一個長爲 \(n\) 含有
abc?
的字符串,?
多是abc
中的任意一個,求全部可能的無?
字符串中,子序列abc
出現的次數.結果須要 mod \(1e9 + 7\)
3 ≤ n ≤ 200000
*2000
dp
經過數據大小和題目所問的,咱們能夠很快得出大體思路:時間複雜度爲 \(\mathcal{O}(n)\) 的線性dp。
假如是 dp ,咱們確定須要記錄一些東西才能保證在 \(\mathcal{O(1)}\) 的時間內進行狀態轉移,而且須要考慮記錄什麼和 ?
如何進行處理。
因爲咱們只須要考慮 abc
,所以咱們能夠只記錄:
a
的數量 \(f[0]\)ab
的數量 \(f[1]\)abc
的數量 \(f[2]\)當沒有遇到 ?
時轉移方程很是簡單,這裏就不作贅述。
下面考慮當須要疑問號的狀況便可:
首先,咱們清楚疑問號能夠變爲 a,b,c
任意一種的,用生物學的知識去想有點像分裂的過程:
當碰到 ?
號時,會在原有的基礎上出現 \(3\) 種新狀況。
而他們各自又繼承了 cur的全部值。所以:
這對了嗎?,實際上這樣寫表明你沒有理解其核心。須要知道的最開始只擁有 \(1\) 種狀況,但每遇到一個 ?
會分裂出 \(3\) 種狀況,不妨假設 ?
的個數爲 \(c_q\) 。則當前存在 \(3^{c_q}\) 種狀況,因而你每次增長都須要考慮全部的狀況。而上述方程中:a -> ab
和 ab -> abc
的轉移自帶魯棒性已經考慮了這個問題,而 null -> a
的過程則沒有考慮。
所以,咱們須要記錄當前空間中存在狀況的總個數 base
,當遇到 ?
時更新 base
的值。
作這種 \(\mathcal{O}(1)\) 的計數 dp ,確定是須要記錄某些數據,若須要計數的爲一個具備順序的序列,不妨前綴考慮每一個子段的個數,逐個轉移。
const int maxn = 5; LL f[maxn]; void solve(){ int n = read(); mst(f, 0); string ss; cin >> ss; LL base = 1; for (int i = 1; i <= n; ++ i){ char ch = ss[i - 1]; if (ch == 'a'){ f[0] = (f[0] + base) % MOD; }else if (ch == 'b'){ f[1] = (f[1] + f[0]) % MOD; }else if (ch == 'c'){ f[2] = (f[2] + f[1]) % MOD; }else { f[2] = (3 * f[2] % MOD + f[1]) % MOD; f[1] = (3 * f[1] % MOD + f[0]) % MOD; f[0] = (3 * f[0] % MOD + base) % MOD; base = (1LL * base * 3) % MOD; } // print(f, 3); } cout << f[2] << '\n'; }
UPD:
小號變大號太真實了: