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;
}