構造 800Q . \Large\mathcal{Q}. Q . 給定n n n 和k k k ,找出長度最小的字符串s s s ,使得所有長度爲n n n 的用前k k k 个小寫英文字母組成的字符串都是s s s 的子串。(CF1925A. We Got Everything Covered! )
A . \Large\mathcal{A}. A . s = a b c … x a b c … x … a b c … x s=abc\dots xabc\dots x\dots abc\dots x s = a b c … x a b c … x … a b c … x
Q . \Large\mathcal{Q}. Q . 規定一个數列的求和方法,從前向後遍歷,若這一項大於前一項,按常規方式求和,否則將和清零。在 1
到 n
的全排列中找出和的最大值。(VJwin4D, CF1728B. Best Permutation )
A . \Large\mathcal{A}. A . { If n = 2 k : 2 k − 2 , 2 k − 3 , … , 3 , 2 , 1 , 2 k − 1 , 2 k If n = 2 k + 1 : 1 , 2 k − 1 , 2 k − 2 , 2 k − 3 , … , 3 , 2 , 2 k , 2 k + 1 \begin{cases}\text{If }n=2k: & 2k-2,~ 2k-3,~ \dots,~ 3,~ 2,~ 1,~ 2k-1,~ 2k \\ \text{If }n=2k+1: & 1,~ 2k-1,~ 2k-2,~ 2k-3,~ \dots,~ 3,~ 2,~ 2k,~ 2k+1\end{cases} { If n = 2 k : If n = 2 k + 1 : 2 k − 2 , 2 k − 3 , … , 3 , 2 , 1 , 2 k − 1 , 2 k 1 , 2 k − 1 , 2 k − 2 , 2 k − 3 , … , 3 , 2 , 2 k , 2 k + 1
900Q . \Large\mathcal{Q}. Q . 給定正整數數列{ a n } \lbrace a_n \rbrace { a n } ,構造{ b n } \lbrace b_n \rbrace { b n } ,滿足a i ≠ b i ( 1 ⩽ i ⩽ n ) a_i \ne b_i(1\leqslant i\leqslant n) a i = b i ( 1 ⩽ i ⩽ n ) ,∑ i = 1 n a i = ∑ i = 1 n b i \sum\limits_{i=1}^{n} a_i = \sum\limits_{i=1}^{n} b_i i = 1 ∑ n a i = i = 1 ∑ n b i 。(VJwin14J, CF1856B. Good Arrays )
A . \Large\mathcal{A}. A . 如果某个元素是 1
,那至少給它增加 1
,我們只需要看非 1
的元素減少的量夠不夠給它增加 1
,也就是它們的總和是否大於 n
,再特判 n=1
的情形即可。
1 2 3 4 5 6 ll n = read (), sum = 0 ; for (int i = 0 ; i < n; ++i) { int x = read (); if (x > 1 ) sum += x; } printf ("%s\n" , n > 1 && sum >= n ? "Yes" : "No" );
另一種(或許更容易理解的)思路是:分別計算當前總和以及所需的最小和 wt
。
1 2 3 4 5 6 7 8 ll n = read (), sum = 0 , wt = 0 ; for (int i = 0 ; i < n; ++i) { int x = read (); sum += x; if (x > 1 ) wt += 1 ; else wt += 2 ; } printf ("%s\n" , n > 1 && sum >= wt ? "Yes" : "No" );
事實上上述兩種方法等價。
1800Q . \Large\mathcal{Q}. Q . 構造一個序列,任何集合{ x ∣ 1 ⩽ x ⩽ n ∧ x ≠ k } \lbrace x \mid 1\leqslant x\leqslant n \land x\ne k \rbrace { x ∣ 1 ⩽ x ⩽ n ∧ x = k } 中的數i i i 都可以是某個子序列的元素之和。(CF1966D. Missing Subsequence Sum )
A . \Large\mathcal{A}. A .
引理 如果我們已經能表示1 ∼ s 1\sim s 1 ∼ s ,且擁有數t > s t>s t > s ,則能表示t ∼ t + s t\sim t+s t ∼ t + s 。
問題 1 求一個數組,任何滿足1 ∼ n 1 \sim n 1 ∼ n 的數i i i 都可以是某個子序列的元素之和。
問題 1 的解答 取{ 1 , 2 , 4 , … , 2 w } \lbrace 1,~2,~4,~\dots,~2^{w} \rbrace { 1 , 2 , 4 , … , 2 w } ,其中2 w ⩾ n 2^w\geqslant n 2 w ⩾ n ,具体地應取⌈ log 2 ( n ) ⌉ − 1 \lceil\log_2(n)\rceil-1 ⌈ log 2 ( n ) ⌉ − 1 。爲敘述方便,以下記w = ⌈ log 2 ( n ) ⌉ − 1 w=\lceil\log_2(n)\rceil - 1 w = ⌈ log 2 ( n ) ⌉ − 1 。 問題 2 求一個數組,所有子序列的和恰好是1 ∼ n 1 \sim n 1 ∼ n 。
問題 2 的解答 注意到取{ 1 , 2 , 4 , … , 2 w − 1 } \lbrace 1,~2,~4,~\dots,~2^{w-1} \rbrace { 1 , 2 , 4 , … , 2 w − 1 } 可表示1 ∼ 2 w − 1 1 \sim 2^{w}-1 1 ∼ 2 w − 1 ,爲了恰好表示到n n n ,希望表示? ∼ n ? \sim n ? ∼ n ,根據引理,只需擁有數n − ( 2 w − 1 ) n-(2^{w}-1) n − ( 2 w − 1 ) 即可,因此我們取{ 1 , 2 , 4 , … , 2 w − 1 , n − ( 2 w − 1 ) } \lbrace 1,~2,~4,~\dots,~2^{w-1},~n-(2^{w}-1) \rbrace { 1 , 2 , 4 , … , 2 w − 1 , n − ( 2 w − 1 ) } 。 問題 3 現在已經恰好能表示1 ∼ k − 1 1\sim k-1 1 ∼ k − 1 ,求一個數組,任何滿足k + 1 ∼ n k+1 \sim n k + 1 ∼ n 的數i i i 都可以是某個子序列的元素之和。
問題 3 的解答 根據引理,已經擁有k + 1 k+1 k + 1 ,因此可表示k + 1 ∼ ( k + 1 + k − 1 = 2 k ) k+1\sim (k+1+k-1=2k) k + 1 ∼ ( k + 1 + k − 1 = 2 k ) ,若是再擁有2 k + 1 2k+1 2 k + 1 ,因此可表示2 k + 1 ∼ 3 k 2k+1\sim 3k 2 k + 1 ∼ 3 k ,再擁有3 k + 1 3k+1 3 k + 1 ,因此可表示3 k + 1 ∼ 4 k 3k+1\sim 4k 3 k + 1 ∼ 4 k 。當然,此過程不能無限進行,畢竟有步數限制。但幸運的是,當擁有k + 1 , 2 k + 1 , 3 k + 1 k+1,2k+1,3k+1 k + 1 , 2 k + 1 , 3 k + 1 時,我們已經可以表示k + 1 ∼ 6 k + 1 k+1\sim 6k+1 k + 1 ∼ 6 k + 1 了,此時再添加6 k + 2 6k+2 6 k + 2 ,便可表示k + 1 ∼ 12 k + 3 k+1\sim 12k+3 k + 1 ∼ 1 2 k + 3 ,如此倍增,就能表示題設要求的所有數。 原問題的解答 根據問題 2,先取{ 1 , 2 , 4 , … , 2 v − 1 , k − ( 2 v − 1 ) } \lbrace 1,~2,~4,~\dots,~2^{v-1},~k-(2^{v}-1) \rbrace { 1 , 2 , 4 , … , 2 v − 1 , k − ( 2 v − 1 ) } ,根據問題 3,再取{ k + 1 , 2 k + 1 , 3 k + 1 , 2 ( 3 k + 1 ) , 2 2 ( 3 k + 1 ) , … } \lbrace k+1,~2k+1,~3k+1,~2(3k+1),~2^2(3k+1),~\dots\rbrace { k + 1 , 2 k + 1 , 3 k + 1 , 2 ( 3 k + 1 ) , 2 2 ( 3 k + 1 ) , … } ,即是問題的答案。
1 2 3 4 5 6 7 8 9 10 int n = read (), k = read ();int bit = 0 ; while ((1ll << bit) <= k) ++bit; --bit;vector<int > ans; for (int i = 0 ; i < bit; ++i) ans.push_back (1ll << i);if (k - (1ll << bit)) ans.push_back (k - (1ll << bit));if (k + 1 <= n) ans.push_back (k + 1 );if (2 * k + 1 <= n) ans.push_back (2 * k + 1 );if (3 * k + 1 <= n) ans.push_back (3 * k + 1 );for (int x = 6 * k + 2 ; x <= n; x <<= 1 ) ans.push_back (x);print (ans);
Q . \Large\mathcal{Q}. Q . 給定n n n ,輸出一个數列,其中包含n n n 个遞增子列。(CF1922E. Increasing Subsequences )
A . \Large\mathcal{A}. A . 注意到{ 0 , 1 , … , x − 1 } \{0,1,\dots,x-1\} { 0 , 1 , … , x − 1 } 中有2 x 2^x 2 x 个遞增子列,我們對n n n 作二進制拆分,即n = 2 a 0 + 2 a 1 + ⋯ + 2 a k n=2^{a_0}+2^{a_1}+\dots+2^{a_k} n = 2 a 0 + 2 a 1 + ⋯ + 2 a k ,首先輸出0 ∼ a k − 1 0\sim a_k-1 0 ∼ a k − 1 ,對於其它二進制位,可以錯位構造a i a^i a i 个數,但爲了節約輸出的个數,我們藉助第一位輸出的數,直接輸出a i a_i a i 即可。最終的輸出結果是0 , 1 , … , a k − 1 , a k − 1 , a k − 2 , … , a 0 0,1,\dots,a_k-1,a_{k-1},a_{k-2},\dots,a_0 0 , 1 , … , a k − 1 , a k − 1 , a k − 2 , … , a 0 。
1 2 3 4 5 6 7 8 ll n = read (); vector<int > ans; ll tmp = n, bit = -1 ; while (tmp) ++bit, tmp >>= 1 ; for (int i = 0 ; i < bit; ++i) ans.emplace_back (i); while (bit--) if (n & (1ll << bit)) ans.emplace_back (bit); printf ("%lld\n" , ans.size ());for (auto i : ans) printf ("%d " , ans[i]);printf ("\n" );
1900Q . \Large\mathcal{Q}. Q . 给定n , k n,k n , k ,构造n n n 个四元组,满足所有四元组的所有元素互不相同,且每个四元组的最大公约数皆为k k k 。求所有元素最大值最小的一组构造。
A . \Large\mathcal{A}. A . 首先把所有四元组除以k k k ,那么所有四元组的最大公约数为1 1 1 。注意到,任意一个四元组都只能存在一个偶数,至少三个奇数,于是元素最大值的下界为6 ( n − 1 ) + 5 = 6 n − 1 6(n-1)+5=6n-1 6 ( n − 1 ) + 5 = 6 n − 1 。另一方面,每个四元组取6 i + 1 , 6 i + 2 , 6 i + 3 , 6 i + 5 ( 0 ⩽ i < n ) 6i+1,6i+2,6i+3,6i+5(0\leqslant i<n) 6 i + 1 , 6 i + 2 , 6 i + 3 , 6 i + 5 ( 0 ⩽ i < n ) 。
2300Q . \Large\mathcal{Q}. Q . 每次操作可選擇一个二元组( x i , y i ) (x_i,y_i) ( x i , y i ) ,使得a x i a_{x_i} a x i 和a y i a_{y_i} a y i 的值變爲f ( a x i , a y i ) f(a_{x_i},a_{y_i}) f ( a x i , a y i ) 。f ( x , y ) f(x,y) f ( x , y ) 的值未知,但對於相同的x , y x,y x , y ,f ( x , y ) f(x,y) f ( x , y ) 的值相同。給出一種操作方案使任意函數f f f 經過若干次操作後數列中最多只有2 2 2 个不同的數。(VJwin7F, CF1408F. Two Different )
A . \Large\mathcal{A}. A . 顯然,若數列的長度是n = 2 k n=2^k n = 2 k ,可分成2 k − 1 2^{k-1} 2 k − 1 組,兩兩操作,再錯位着操作,最終會全部相同。比如對於n = 8 n=8 n = 8 ,可以這樣操作:| 1 2 3 4 5 6 7 8 || 1 3 2 4 5 7 6 8 || 1 5 2 6 3 7 4 8 |
。那麼如果不是2 2 2 的冪呢?比如n = 9 n=9 n = 9 ,劃分爲9 = 8 + 1 = 4 + 5 9=8+1=4+5 9 = 8 + 1 = 4 + 5 ?實操後發現不行,實際上,不一定做加法拆分,可以先對前8 8 8 个操作,然後借用第2 8 2~8 2 8 个元素和後面第9 9 9 个元素一併操作,也就是 | 1 2 3 4 5 6 7 8 || 1 3 2 4 5 7 6 8 || 1 5 2 6 3 7 4 8 |||| 2 3 4 5 6 7 8 9 || 2 4 3 5 6 8 7 9 || 2 6 3 7 4 8 5 9 |
。現在只要把這些數字輸出來就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int cnt = -1 , t = n;while (t) { cnt++; t >>= 1 ; }t = 1 << cnt; for (int i = cnt; i >= 1 ; --i) { for (int j = 1 ; j <= (1 << i) / 2 ; j++) { for (int k = 1 ; k <= t / (1 << i); k++) { printf ("%d %d\n" , k + t * 2 / (1 << i) * (j - 1 ), k + t * 2 / (1 << i) * (j - 1 ) + t / (1 << i)); } } } for (int i = cnt; i >= 1 ; --i) { for (int j = 1 ; j <= (1 << i) / 2 ; j++) { for (int k = 1 ; k <= t / (1 << i); k++) { printf ("%d %d\n" , n - t + k + t * 2 / (1 << i) * (j - 1 ), n - t + k + t * 2 / (1 << i) * (j - 1 ) + t / (1 << i)); } } }
輸出練習題
BUC1E 杨辉三角