T1:Divisible

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    rep(i, n) {
        if (a[i]%k == 0) {
            cout << a[i]/k << ' ';
        }
    }
    
    return 0;
}

T2:Substring

暴力枚举,然后用 std::set 维护一下所有的子串即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    string s;
    cin >> s;
    int n = s.size();
    
    set<string> st;
    rep(l, n) {
        for (int r = l; r < n; ++r) {
            string t = s.substr(l, r-l+1);
            st.insert(t);
        }
    }
    
    cout << st.size() << '\n';
    
    return 0;
}

T3:Ideal Holidays

\(w = a+b\)
因为 \(w\) 天形成一个周期,所以可以将所有的 \(d_i\) 分别对 \(w\) 取模
然后对序列 \(d\) 做升序排序
我们只需判定能否让这 \(n\) 个计划都出现在连续的 \(a\) 天里
注意到由于周期性,这 \(n\) 个计划一定会出现在一个圆上,我们只需枚举应该断开相邻两点之间的那部分,然后判定这断开的这段的长度(不包括两端点)是否超过 \(b\) 即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n, a, b;
    cin >> n >> a >> b;
    int w = a+b;
    
    vector<int> d(n);
    rep(i, n) cin >> d[i];
    rep(i, n) d[i] %= w;
    sort(d.begin(), d.end());
    rep(i, n) d.push_back(d[i]+w);
    
    rep(i, d.size()-1) {
        if (d[i+1]-d[i] >= b+1) {
            puts("Yes");
            return 0;
        }
    }
    
    puts("No");
    
    return 0;
}

T4:Popcount and XOR

\(c\)1 的个数为 \(k\)
显然 \(k\) 不会超过 \(a+b\)
\(d = a+b-k\)
\(x\)\(y\) 中有 \(\frac{d}{2}\)1 的位置是相同的,这样异或起来 \(c\) 中相应位置就会变成 0
然后 \(x\) 中就贡献了 \(a-d\)1\(y\) 中就贡献了 \(b-d\)1
然后就容易构造了

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

const int M = 60;

int pc(ll x) {
    return __builtin_popcountll(x);
}

ll tos(vector<int> x) {
    ll res = 0;
    rep(i, M) res |= (ll)x[i]<<i;
    return res;
}

int main() {
    int a, b; ll c;
    cin >> a >> b >> c;
    
    ll one = pc(c);
    ll zero = M-one;
    
    ll d = a+b-one;
    if (d < 0 or d%2 == 1) {
        puts("-1");
        return 0;
    } 
    
    d /= 2;
    a -= d;
    b -= d;
    if (d > zero or a < 0 or b < 0) {
        puts("-1");
        return 0;
    }
    
    vector<int> x(M), y(M); 
    vector<int> i0, i1;
    rep(i, M) {
        if (c>>i&1) i1.push_back(i);
        else i0.push_back(i);
    }
    
    rep(j, d) {
        int i = i0[j];
        x[i] = y[i] = 1;
    }
    rep(j, one) {
        int i = i1[j];
        if (j < a) x[i] = 1;
        else y[i] = 1;
    }
    
    cout << tos(x) << ' ' << tos(y) << '\n';
    
    return 0;
}

T5:Set Add Query

感觉是一道挺唬的题,通过画图可以发现 \(a_i\) 的贡献其实就是 \(i\) 存在于集合 \(S\) 中的时间段内的贡献累加和,那么我们用前缀和来解决即可,具体地,\(i\) 在进入集合 \(S\) 的前一刻 \(a_i\) 需要减去当前集合的大小,然后在删除 \(i\) 的前一刻 \(a_i\) 需要加上当前集合的大小

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

int main() {
    int n, q;
    cin >> n >> q;
    
    vector<ll> a(n);
    unordered_set<int> st;
    ll s = 0;
    rep(qi, q) {
        int x;
        cin >> x;
        --x;
        if (st.count(x)) {
            a[x] += s;
            st.erase(x);
        }
        else {
            a[x] -= s;
            st.insert(x);
        }
        s += st.size();
    }
    
    for (int x : st) a[x] += s;
    
    rep(i, n) cout << a[i] << ' ';
    
    return 0;
}

T6:Non-overlapping Squares

原题:[APIO2009] 采油区域

大概有两种摆放

其中每个正方形可以在不和其他正方形相交的情况下做上下左右自由移动

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

inline void chmax(ll& x, ll y) { if (x < y) x = y; }

int main() {
    int n, m;
    cin >> n >> m;
    
    vector a(n, vector<int>(n));
    rep(i, n)rep(j, n) cin >> a[i][j];
    
    vector s(n+1, vector<ll>(n+1));
    rep(i, n)rep(j, n) s[i+1][j+1] = a[i][j];
    rep(i, n)rep(j, n) s[i+1][j+1] += s[i+1][j];
    rep(i, n)rep(j, n) s[i+1][j+1] += s[i][j+1];
    
    int w = n-m+1;
    vector d(w, vector<ll>(w));
    rep(i, w)rep(j, w) {
        ll now = s[i+m][j+m];
        now -= s[i][j+m];
        now -= s[i+m][j];
        now += s[i][j];
        d[i][j] = now;
    }
    
    ll ans = 0;
    rep(ri, 4) {
        vector<ll> col(w);
        rep(j, w)rep(i, w) chmax(col[j], d[i][j]);
        
        auto ru = d, rd = d;
        rep(i, w) for (int j = w-1; j >= 0; --j) {
            if (i) chmax(ru[i][j], ru[i-1][j]);
            if (j+1 < w) chmax(ru[i][j], ru[i][j+1]);
        }
        for (int i = w-1; i >= 0; --i) {
            for (int j = w-1; j >= 0; --j) {
                if (i+1 < w) chmax(rd[i][j], rd[i+1][j]);
                if (j+1 < w) chmax(rd[i][j], rd[i][j+1]);
            }
        }
        
        ll lmax = 0;
        rep(j, w-m) {
            chmax(lmax, col[j]);
            { // type A
                ll mmax = 0;
                for (int nj = j+m; nj < w; ++nj) {
                    chmax(mmax, col[nj]);
                    int mj = nj+m;
                    if (mj >= w) break;
                    ll rmax = ru[w-1][mj];
                    chmax(ans, lmax+mmax+rmax);
                }
            }
            { // type B
                int nj = j+m;
                rep(i, w-m) {
                    ll umax = ru[i][nj];
                    ll dmax = rd[i+m][nj];
                    chmax(ans, lmax+umax+dmax);
                }
            }
        }
        auto old = d;
        rep(i, w)rep(j, w) d[i][j] = old[w-1-j][i];
    }
    
    cout << ans << '\n';
    
    return 0;
}