A: Little Sub and Pascal's Trianglenode
Solved.c++
題意:數據結構
求楊輝三角第n行奇數個數ide
思路:ui
薛聚聚說找規律,16說Lucas編碼
答案是 $2^p \;\;p 爲 n - 1 中 以2進製表示下1的個數$spa
證實code
$Ans = \sum\limits_0^n C_n^i \;\%\; 2 = \sum\limits_0^n C_{\frac{n}{2}}^{\frac{i}{2}} \cdot C_{n\;\%\;2}^{i\;\%\;2}$blog
咱們考慮 $C_{n \;\%\; 2}^{i \;\%\; 2}$ 一共有四種取值排序
$C_0^0 \;\; C_0^1\;\; C_1^0 \;\; C_1^1$
咱們發現 只有 $C_0^1的值爲0 其餘三個值都爲1$
那麼咱們再考慮$C_n^i 這個式子$
它經過盧卡斯定理分解 實際上能夠寫成
咱們先假設
$i 以二進制表示爲$
$a_1, a_2, \cdots a_k$
$n 以二進制表示爲$
$b_1, b_2, \cdots b_k$
那麼 $C_n^i = C_{b_1}^{a_1} \cdot C_{b_2}^{a_2} \cdots C_{b_k}^{a_k}$
那麼咱們發現,
要知足$C_n^i\;\%\; 2 = 1 \;\;$
$那麼在b_y = 1的位置上,i在對應位置上取0或者1均可以$
在$b_y = 0 的位置上,i在對應位置的取值已經固定 是 0$
那麼$i的取值一共有2^p p 爲(n - 1)以2進製表示下1的個數$
爲何是$n - 1 \;\;由於楊輝三角是從第0行開始的$
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 ll n; 8 9 int main() 10 { 11 int t; 12 scanf("%d", &t); 13 while(t--) 14 { 15 scanf("%lld", &n); 16 n--; 17 ll tmp = 0; 18 while(n) 19 { 20 if(n & 1) tmp++; 21 n >>= 1; 22 } 23 ll ans = 1ll << tmp; 24 printf("%lld\n", ans); 25 } 26 return 0; 27 }
B:Little Sub and his Geometry Problem
Solved.
題意:
一個點的權值定義爲它到左下角全部點的曼哈頓距離
q次查詢, 每次查詢權值爲c的點的個數
思路:
$給出的點沿着x軸正方向, y軸正方向都是嚴格單調遞增的。$
$所以能夠枚舉x軸, 動態維護左下角點個數以及權值, 向右走的同時$
$將橫座標相同, 縱座標<=當前位置的點假如, 向下走的時候將縱座標相同給的點移除$
$當前權值爲c時 ans++$
(薛聚聚:不會寫題解啊)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 typedef unsigned long long ull; 7 8 const double eps = 1e-8; 9 const ll MOD = 1e9 + 7; 10 const ll INFLL = 0x3f3f3f3f3f3f3f3f; 11 const int INF = 0x3f3f3f3f; 12 const int maxn = 1e5 + 10; 13 14 int n, k; 15 ll sum, cnt; 16 ll sum_arr[maxn], cnt_arr[maxn]; 17 ll ans[20]; 18 19 struct node { 20 int x, y; 21 node() {} 22 node(int x, int y) :x(x), y(y) {} 23 bool operator < (const node &other) const 24 { 25 return x == other.x ? y < other.y : x < other.x; 26 } 27 }P[maxn]; 28 29 ll solve(ll c) 30 { 31 cnt = sum = 0; 32 memset(sum_arr, 0, sizeof sum_arr); 33 memset(cnt_arr, 0, sizeof cnt_arr); 34 int index = 1; 35 int ans = 0; 36 int y = n; 37 for (int x = 1; x <= n; ++x) 38 { 39 while (index <= k && P[index].x <= x) 40 { 41 if (P[index].y <= y) 42 { 43 cnt++; 44 sum += P[index].x + P[index].y; 45 sum_arr[P[index].y] += P[index].x + P[index].y; 46 cnt_arr[P[index].y]++; 47 } 48 ++index; 49 } 50 while ((x + y) * cnt - sum > c) 51 { 52 sum -= sum_arr[y]; 53 cnt -= cnt_arr[y]; 54 --y; 55 } 56 if ((x + y) * cnt - sum == c) ++ans; 57 } 58 return ans; 59 } 60 61 void RUN() 62 { 63 int t; 64 scanf("%d", &t); 65 while (t--) 66 { 67 scanf("%d %d", &n, &k); 68 for (int i = 1; i <= k; ++i) scanf("%d %d", &P[i].x, &P[i].y); 69 sort(P + 1, P + 1 + k); 70 int q; 71 scanf("%d", &q); 72 for (int i = 1; i <= q; ++i) 73 { 74 ll c; 75 scanf("%lld\n", &c); 76 ans[i] = solve(c); 77 } 78 for (int i = 1; i <= q; ++i) printf("%lld%c", ans[i], " \n"[i == q]); 79 } 80 } 81 82 int main() 83 { 84 #ifdef LOCAL_JUDGE 85 freopen("Text.txt", "r", stdin); 86 #endif // LOCAL_JUDGE 87 88 RUN(); 89 90 #ifdef LOCAL_JUDGE 91 fclose(stdin); 92 #endif // LOCAL_JUDGE 93 return 0; 94 }
E:Little Sub and Mr.Potato's Math Problem
Solved.
題意:
給出n, k
將n個數按照字典序排序, k所在的位置爲m
如今給出k, m 求最小的n
思路:
當k爲10的整數倍, 那麼它必定在第$log_{10^k}$
$隨後統計當n=k的時候, 排在k前面的個數,和m比較, 判斷是否合法$
$接着不斷增長n, 統計每次增加排在k前面的個數, 隨後輸出n$
(薛聚聚:不會寫題解啊)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 typedef unsigned long long ull; 7 8 const double eps = 1e-8; 9 const ll MOD = 1e9 + 7; 10 const ll INFLL = 0x3f3f3f3f3f3f3f3f; 11 const int INF = 0x3f3f3f3f; 12 const int maxn = 1e5 + 10; 13 14 ll k, m; 15 int arr[maxn]; 16 ll pow_10[10]; 17 18 void Init() 19 { 20 pow_10[0] = 1; 21 for (int i = 1; i <= 18; ++i) 22 { 23 pow_10[i] = pow_10[i - 1] * 10; 24 } 25 } 26 27 void solve() 28 { 29 ll num = 1; 30 for (int i = 1;; ++i) 31 { 32 if (num > k) break; 33 else if (num == k) 34 { 35 if (i == m) 36 { 37 printf("%lld\n", k); 38 return; 39 } 40 else 41 { 42 puts("0"); 43 return; 44 } 45 } 46 num *= 10; 47 } 48 int len = 0; 49 num = k; 50 while (num) 51 { 52 arr[++len] = num % 10; 53 num /= 10; 54 } 55 reverse(arr + 1, arr + 1 + len); 56 ll ans = 0; 57 num = 0; 58 for (int i = 1; i <= len; ++i) 59 { 60 num = num * 10 + arr[i]; 61 ans += num - pow_10[i - 1]; 62 if (i != len) ++ans; 63 } 64 if (ans >= m) 65 { 66 puts("0"); 67 return; 68 } 69 else if (ans == m - 1) 70 { 71 printf("%lld\n", k); 72 return; 73 } 74 while (1) 75 { 76 len++; 77 num *= 10; 78 if (ans + num - pow_10[len - 1] >= m - 1) 79 { 80 ans = pow_10[len - 1] + m - ans - 2; 81 printf("%lld\n", ans); 82 return; 83 } 84 ans += num - pow_10[len - 1]; 85 } 86 } 87 88 void RUN() 89 { 90 Init(); 91 int t; 92 scanf("%d", &t); 93 while (t--) 94 { 95 scanf("%lld %lld", &k, &m); 96 solve(); 97 } 98 } 99 100 int main() 101 { 102 #ifdef LOCAL_JUDGE 103 freopen("Text.txt", "r", stdin); 104 #endif // LOCAL_JUDGE 105 106 RUN(); 107 108 #ifdef LOCAL_JUDGE 109 fclose(stdin); 110 #endif // LOCAL_JUDGE 111 return 0; 112 }
F:Little Sub and a Game
Unsolved.
題意:
有兩個玩家$A, B 剛開始有一個變量v = 0$
$A玩家有N個pair, B玩家有M個pair \;\; pair 爲(x, y) A玩家N次操做,每次選擇x_i 或者 y_i 來異或v B玩家有M次操做$
$A玩家先進行N次操做, B玩家再進行M次操做$
A玩家想讓$v儘可能大,B玩家想讓v儘可能小$
兩個玩家都採用最優策略,求最後$v$的值
G:Little Sub and Tree
Solved.
題意:
給出一個無根樹,選取$k個點對全部點進行編碼$
按以下方式進行編碼
$令選取的k個點爲 s_1, s_2 \cdots s_k$
編出的碼有$k位$
$對於u來講,第i位的編碼爲 s_i -> u的簡單路徑上的點的總數$
思路:
若是是一條鏈的話 那麼取兩端的一個就能夠了
那麼咱們考慮一棵樹中,若是某個節點的兒子對應的子樹是一條鏈
那麼這條鏈是能夠被縮點成一個葉節點 而對答案沒有影響
那麼如今樹就被咱們簡化成了 只有葉節點的子樹
首先注意到,一棵子樹內節點的區分和這棵子樹外的點的選取是沒有關係的
那麼咱們考慮 一個點對應的兒子當中,若是有$x個葉節點$
那麼這x個節點要想被區分,就須要取$x - 1$ 個
再考慮一個點的兒子對應的子樹,若是子樹內都被區分了,那麼合併起來也是被區分的
那麼考慮選誰做爲根
只要根不在鏈上就能夠了,由於若是在鏈上會對縮點產生影響
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int t, n, root, d[N], fa[N]; 6 vector <int> G1[N], G2[N], res; 7 8 int pre(int u) 9 { 10 int id = -1; 11 int cnt = G1[u].size() - 1; 12 if (cnt == 0) return u; 13 for (auto v : G1[u]) if (v != fa[u]) 14 { 15 fa[v] = u; 16 id = pre(v); 17 G2[u].push_back(id); 18 } 19 if (cnt == 1 && u != root) return id; 20 else return u; 21 } 22 23 void DFS(int u) 24 { 25 int need = 0; 26 for (auto v : G2[u]) if (v != fa[u] && !d[v]) 27 ++need; 28 --need; 29 for (auto v : G2[u]) if (v != fa[u]) 30 { 31 fa[v] = u; 32 if (!d[v] && need > 0) 33 { 34 --need; 35 res.push_back(v); 36 } 37 DFS(v); 38 } 39 } 40 41 int main() 42 { 43 scanf("%d", &t); 44 while (t--) 45 { 46 scanf("%d", &n); 47 for (int i = 1; i <= n; ++i) 48 { 49 G1[i].clear(); 50 G2[i].clear(); 51 d[i] = -1; 52 fa[i] = 0; 53 } 54 res.clear(); 55 root = -1; 56 57 for (int i = 1, u, v; i < n; ++i) 58 { 59 scanf("%d%d", &u, &v); 60 G1[u].push_back(v); 61 G1[v].push_back(u); 62 ++d[u]; ++d[v]; 63 } 64 if (n == 2) 65 { 66 puts("1\n1"); 67 continue; 68 } 69 for (int i = 1; i <= n; ++i) if (d[i] > 1) 70 { 71 root = i; 72 break; 73 } 74 if(root == -1) 75 { 76 int ans = 0; 77 for(int i = 1; i <= n; ++i) if(d[i] == 0) ans = i; 78 printf("1\n%d\n", ans); 79 continue; 80 } 81 pre(root); 82 DFS(root); 83 //puts("bug"); 84 //for (int i = 1; i <= n; ++i) printf("%d %d\n", i, fa[i]); 85 //puts("bug"); 86 int k = res.size(); 87 printf("%d\n", k); 88 for (int i = 0; i < k; ++i) printf("%d%c", res[i], " \n"[i == k - 1]); 89 } 90 return 0; 91 }
I:Little Sub and Isomorphism Sequences
Solved.
題意:
有一個$A[], 兩種操做$
思路:
考慮最長同構子串確定會有重疊部分,那麼兩端出去的部分就是不一樣的部分
那麼這個不一樣的部分讓它長度爲1便可,由於多餘的長度是沒有用的
那麼題意就能夠轉化爲 找一個最長的子串,使得兩端相同便可
將數據離散化 開2e5個set維護每一個數的位置
而後用數據結構 維護答案的最大值 便可
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 200010 5 int t, n, m, a[N], b[N]; 6 struct qnode 7 { 8 int op, x, y; 9 void scan() 10 { 11 scanf("%d", &op); 12 if (op == 1) 13 { 14 scanf("%d%d", &x, &y); 15 b[++b[0]] = y; 16 } 17 } 18 }q[N]; 19 set <int> s[N]; 20 namespace SEG 21 { 22 int a[N << 2]; 23 void build(int id, int l, int r) 24 { 25 a[id] = -1; 26 if (l == r) return; 27 int mid = (l + r) >> 1; 28 build(id << 1, l, mid); 29 build(id << 1 | 1, mid + 1, r); 30 } 31 void update(int id, int l, int r, int pos, int v) 32 { 33 if (l == r) 34 { 35 a[id] = v; 36 return; 37 } 38 int mid = (l + r) >> 1; 39 if (pos <= mid) update(id << 1, l, mid, pos, v); 40 else update(id << 1 | 1, mid + 1, r, pos, v); 41 a[id] = max(a[id << 1], a[id << 1 | 1]); 42 } 43 } 44 void Hash() 45 { 46 sort(b + 1, b + 1 + b[0]); 47 b[0] = unique(b + 1, b + 1 + b[0]) - b - 1; 48 for (int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + 1 + b[0], a[i]) - b; 49 for (int i = 1; i <= m; ++i) if (q[i].op == 1) q[i].y = lower_bound(b + 1, b + 1 + b[0], q[i].y) - b; 50 } 51 52 int main() 53 { 54 scanf("%d", &t); 55 while (t--) 56 { 57 scanf("%d%d", &n, &m); 58 SEG::build(1, 1, n + m); 59 for (int i = 1; i <= n + m; ++i) s[i].clear(); b[0] = 0; 60 for (int i = 1; i <= n; ++i) scanf("%d", a + i), b[++b[0]] = a[i]; 61 for (int i = 1; i <= m; ++i) q[i].scan(); Hash(); 62 for (int i = 1; i <= n; ++i) s[a[i]].insert(i); 63 for (int i = 1; i <= n + m; ++i) if (s[i].size() >= 2) 64 SEG::update(1, 1, n + m, i, *s[i].rbegin() - *s[i].begin()); 65 for (int i = 1; i <= m; ++i) 66 { 67 if (q[i].op == 1) 68 { 69 int v = a[q[i].x], x = q[i].x, y = q[i].y; 70 s[v].erase(x); 71 SEG::update(1, 1, n + m, v, s[v].size() >= 2 ? *s[v].rbegin() - *s[v].begin() : -1); 72 a[q[i].x] = y; 73 v = y; 74 s[v].insert(x); 75 SEG::update(1, 1, n + m, v, s[v].size() >= 2 ? *s[v].rbegin() - *s[v].begin() : -1); 76 } 77 else printf("%d\n", SEG::a[1]); 78 } 79 } 80 return 0; 81 }