怎样爆零 CSP-S2 2019

旧城冷巷雨未停 提交于 2019-12-05 02:42:08

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

正解

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!