按照順序來。ios
Median Sumide
大意:函數
給你一個集合,求其全部非空子集的權值的中位數。this
某集合的權值即爲其元素之和。spa
1 <= n <= 2000 3d
解:code
集合配對,每一個集合都配對它的補集。blog
最大的那個沒有配對,因此求(原集合的權值 + 1) >> 1,不小於這個的第一個即爲所求。字符串
用bitset實現可行性揹包。get
1 #include <cstdio> 2 #include <bitset> 3 4 const int N = 2010; 5 6 std::bitset<N * N> bt; 7 8 int a[N]; 9 10 int main() { 11 int n, tot = 0; 12 scanf("%d", &n); 13 for(int i = 1; i <= n; i++) { 14 scanf("%d", &a[i]); 15 } 16 for(int i = 1; i <= n; i++) { 17 bt |= (bt << a[i]); 18 bt[a[i]] = 1; 19 tot += a[i]; 20 } 21 tot = (tot + 1) >> 1; 22 while(bt[tot] == 0) { 23 tot++; 24 } 25 printf("%d", tot); 26 return 0; 27 }
大意:
輸入 N 個數字和 K 。
若是對於全部包含 Ai ,且和不小於 K 的集合,去掉 Ai 後和還不小於 K ,那麼 Ai 就是 no need 的。
問有多少個元素是 no need 的。
1 <= n, k <= 5000
解:
no need 的必定是連續最小的一段,證實以下:
若 x need,且 y > x
對於每一個包含 x 且 >= K 的集合,去掉 x 必定小於 K 。
若此集合包含 y ,則去掉 y 也小於 K 。
若此集合不包含 y ,則把 x 換成 y 便可。
這樣證實了全部含x的集合。
對於某些把 y 換成 x 就會小於 K 的集合,
把 y 換成 0 也小於 K 。
證畢。
而後二分check。
check函數用上一題的思想,對於 x ,只要去掉 x 的集合和沒有在[k - x, k)之間的,x 即爲 no need
若 x >= k,單 x 元素即爲所求,x 爲 need。
1 #include <cstdio> 2 #include <bitset> 3 #include <algorithm> 4 5 const int N = 5010; 6 7 std::bitset<N> bt; 8 9 int n, a[N], k; 10 11 inline bool check(int x) { 12 if(a[x] >= k) { 13 return 1; 14 } 15 bt.reset(); 16 for(int i = 1; i <= n; i++) { 17 if(i == x) { 18 continue; 19 } 20 if(a[i] > N - 1) { 21 break; 22 } 23 bt |= (bt << a[i]); 24 bt.set(a[i]); 25 } 26 for(int i = k - a[x]; i < k; i++) { 27 if(bt[i]) { 28 return 1; 29 } 30 } 31 return 0; 32 } 33 34 int main() { 35 scanf("%d%d", &n, &k); 36 for(int i = 1; i <= n; i++) { 37 scanf("%d", &a[i]); 38 } 39 std::sort(a + 1, a + n + 1); 40 int l = 1, r = n, mid; 41 while(l < r) { 42 mid = (l + r + 1) >> 1; 43 if(check(mid)) { 44 r = mid - 1; 45 } 46 else { 47 l = mid; 48 } 49 } 50 if(r == 1 && check(1)) { 51 r = 0; 52 } 53 printf("%d", r); 54 return 0; 55 }
大意:
在 n * m 的區域中,輸入 k 個黑格子的位置(x,y)。
對於每一個 3 * 3 的區域,會包含 0 到 9 個黑格子。
求包含 0 ~ 9 個黑格子的 3 * 3 的區域各有多少個?
1 <= m, n <= 10 ^ 9
0 <= k <= 10 ^ 5
解:
每一個黑格子只會對 9 個 3 * 3 的區域產生影響。
注意map的用法: it -> second
1 #include <cstdio> 2 #include <map> 3 #include <algorithm> 4 5 typedef long long LL; 6 7 const int N = 100010; 8 9 struct A { 10 int x, y; 11 A(int x = 0, int y = 0) { 12 this->x = x; 13 this->y = y; 14 } 15 bool operator < (const A &d) const { 16 if(x == d.x) { 17 return y < d.y; 18 } 19 return x < d.x; 20 } 21 bool operator == (const A &d) const { 22 return x == d.x && y == d.y; 23 } 24 }a[N * 9]; 25 26 std::map<A, int> mp; 27 28 int ans[10]; 29 30 int main() { 31 int m, n, k; 32 scanf("%d%d%d", &n, &m, &k); 33 for(int i = 1, x, y; i <= k; i++) { 34 scanf("%d%d", &x, &y); 35 for(int j = 0; j < 3; j++) { 36 for(int k = 0; k < 3; k++) { 37 if(x + j > n || y + k > m || x + j < 3 || y + k < 3) { 38 continue; 39 } 40 mp[A(x + j, y + k)]++; 41 } 42 } 43 } 44 std::map<A, int>::iterator it = mp.begin(); 45 int tot = 0; 46 for(; it != mp.end(); it++) { 47 tot++; 48 ans[it->second]++; 49 } 50 printf("%lld\n", 1ll * (m - 2) * (n - 2) - 1ll * tot); 51 for(int i = 1; i <= 9; i++) { 52 printf("%d\n", ans[i]); 53 } 54 return 0; 55 }
大意:
給定 n 個 a , m 個 b, k 個 c
求所組成的字符串的最小循環表示法的最大字典序。
解(結論):把這些一個一個的字符放入multiset,每次取字典序最大最小的合併放回去。
最後的即爲所求。
1 #include <cstdio> 2 #include <set> 3 #include <iostream> 4 5 using std::string; 6 7 std::multiset<string> s; 8 9 int main() { 10 int n; 11 scanf("%d", &n); 12 for(int i = 1; i <= n; i++) { 13 s.insert("a"); 14 } 15 scanf("%d", &n); 16 for(int i = 1; i <= n; i++) { 17 s.insert("b"); 18 } 19 scanf("%d", &n); 20 for(int i = 1; i <= n; i++) { 21 s.insert("c"); 22 } 23 while(s.size() > 1) { 24 string a = *s.begin(); 25 string b = *(--s.end()); 26 s.erase(s.begin()); 27 s.erase(--s.end()); 28 s.insert((string)(a + b)); 29 } 30 std::cout << *s.begin(); 31 return 0; 32 }
不會...