code
依题意模拟。
95: 这是错的
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ll; int n; ll k; void grayprint(int n, ll k) { // cerr << n << " " << k << endl; if (n == 1) { cout << k; return; } if ((1ull << (n - 1)) > k) { cout << "0"; grayprint(n - 1, k); } else { cout << "1"; grayprint(n - 1, (1ull << n) - k - 1); } } int main() { freopen("code.in", "r", stdin); freopen("code.out", "w", stdout); cin >> n >> k; // cerr << n << " " << k << endl; // cerr << "here" << endl; grayprint(n, k); cout << endl; return 0; }
错处在于 grayprint(n - 1, (1ull << n) - k - 1)
. 在 \(n=64\) 时,当然会溢出。而进入此分支,必然有 \(k\ge2^{n-1}\). 进而有\(2^{n-1}-k, 2^{n-1}-k+2^{n-1}, 2^{n-1}-k+2^{n-1}-1\in[0,2^{64})\cap\mathbb{Z}\).
100:
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ll; void grayprint(int n, ll k) { // cerr << n << " " << k << endl; if (n == 1) { cout << k; return; } if ((1ull << (n - 1)) > k) { cout << "0"; grayprint(n - 1, k); } else { cout << "1"; grayprint(n - 1, (1ull << (n - 1)) - k + (1ull << (n - 1)) - 1); } } int main() { int n; ll k; cin >> n >> k; grayprint(n, k); cout << endl; return 0; }
brackets
在链上的问题可以通过存储 \((k_i)_{i=1}^n\) 以外的额外状态 \((p_i)_{i=1}^n\) 来转移,其中 \(p_i\) 表示树根到节点 \(i\) 的串上紧接的合法子串数量。
那么设与节点 \(u\) 匹配的节点为 \(c\),有:
\[\begin{cases} p_u=p_{c-1}+1\\ k_u=k_{u-1}+p_u \end{cases}\]
(对于一个右括号)。其中 \(c\) 容易想到可以在把左括号入栈时存储,出栈时即为对应的 \(c\). 而对于左括号和没有匹配的左括号的的右括号,均有
\[\begin{cases} p_u=0\\ k_u=k_{u-1} \end{cases}\]
那么,将这种解法推广到树上的方法是显然的。只需要在 DFS 函数返回时,撤销对全局栈的操作即可。转移方程变为:
对于可以匹配的右括号:
\[\begin{cases}
p(u)=p(f_c)+1\\
k(u)=k(f_u)+p(u)
\end{cases}\]
对于其余情况:
\[\begin{cases}
p(u)=0\\
k(u)=k(f_u)
\end{cases}\]
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define MAXN 500020 #define MAXM (2 * MAXN) int to[MAXM], nxt[MAXM], hd[MAXN], ne = 0; int n, fa[MAXN]; ll k[MAXN], adj[MAXN]; char ch[MAXN]; stack<int> st; void link(int u, int v) { nxt[++ne] = hd[u]; hd[u] = ne; to[ne] = v; } void calc(int u) { if (ch[u] == '(') { st.push(u); adj[u] = 0; k[u] = k[fa[u]]; for (int i = hd[u]; i; i = nxt[i]) calc(to[i]); st.pop(); } else { if (st.empty()) { adj[u] = 0; k[u] = k[fa[u]]; for (int i = hd[u]; i; i = nxt[i]) calc(to[i]); } else { int c = st.top(); st.pop(); adj[u] = adj[fa[c]] + 1; k[u] = k[fa[u]] + adj[u]; for (int i = hd[u]; i; i = nxt[i]) calc(to[i]); st.push(c); } } } int main() { cin >> n >> (ch + 1); for (int i = 2; i <= n; i++) { cin >> fa[i]; link(fa[i], i); } calc(1); ll ans = 0; for (ll i = 1; i <= n; i++) { ans ^= i * k[i]; cerr << k[i] << " "; } cerr << endl; cout << ans << endl; return 0; }
partition
错解
直观上说,应该尽量使 \(p\) 大。把 \(\{a,b\}\) 与 \(\{a\},\{b\}\) 比较,显然是后者更优(当然是在保证合法性(即 \(a\le b\))的前提下),因为 \((a+b)^2-(a^2+b^2)=2ab>0\).
那么,对于每个数,可以存当前的一段、前一段和,进行贪心。尽量把一个数作为新的一段的开始。
这是错的
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ul; #define MAXN 40000020 #define MAXM 100020 ll a[MAXN], p[MAXM], l[MAXM], r[MAXM], b[MAXM]; int n, typ; void read() { for (int i = 1; i <= n; i++) cin >> a[i]; } void gen() { int x, y, z, m; cin >> x >> y >> z >> b[1] >> b[2] >> m; for (int i = 1; i <= m; i++) cin >> p[i] >> l[i] >> r[i]; for (int i = 3; i <= n; i++) b[i] = (x * b[i - 1] + y * b[i - 2] + z) % (1 << 30); p[0] = 0; for (int j = 1; j <= m; j++) for (int i = p[j - 1] + 1; i <= p[j]; i++) a[i] = (b[i] % (r[j] - l[j] + 1)) + l[j]; } void solve() { bool up = true; for (int i = 2; i <= n; i++) if (a[i] < a[i - 1]) { up = false; break; } if (up) { ul ans = 0; for (int i = 1; i <= n; i++) ans += a[i] * a[i]; cout << ans << endl; return; } ll seg = a[1], prev = -1; ul ans = 0; // bool nmafter = true; for (int i = 2; i < n; i++) { if (a[i] >= seg && seg >= prev) { // start new segment ans += seg * seg; prev = seg; seg = a[i]; // cerr << i << " " << endl; // cerr << i << " " << a[i] << " 1 " << seg << " " << prev << endl; } else { // cerr << abs(a[i] - seg) << " " << abs(a[i + 1] - a[i]) << endl; if (abs(a[i] - seg) < abs(a[i + 1] - a[i]) || (seg + a[i] <= prev)) { // merge with before seg += a[i]; // cerr << i << " " << a[i] << " 2 " << seg << " " << prev << endl; } else { // start new segment ans += seg * seg; prev = seg; seg = a[i]; // cerr << i << " " << a[i] << " 3 " << seg << " " << prev << endl; // cerr << i << " " << endl; } } // cerr << "loop" << endl; } // cerr << endl; // cerr << seg << endl; if (a[n] >= seg && seg >= prev) { ans += seg * seg; ans += a[n] * a[n]; } else { seg += a[n]; ans += seg * seg; } cout << ans << endl; } int main() { freopen("partition.in", "r", stdin); freopen("partition.out", "w", stdout); cin >> n >> typ; if (typ) gen(); else read(); solve(); return 0; }