zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第七场)

    2019牛客暑期多校训练营(第七场)

    题目链接

    A.String

    暴力(dp)即可。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 205;
    int T;
    char s[N];
    int dp[N], pre[N];
    bool check(int x, int y) {
        for(int d = 1; d <= y - x; d++) {
            for(int i = x; i <= y; i++) {
                int j = i + d;
                if(j > y) j = j - y + x - 1;
                if(s[i] != s[j]) {
                    if(s[j] < s[i]) return 0;
                    break ;
                }
            }
        }
        return 1;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> s + 1;
            int n = strlen(s + 1);
            for(int i = 1; i <= n; i++) pre[i] = 0, dp[i] = n + 1;
            for(int i = 1; i <= n; i++) {
                for(int j = 0; j < i; j++) {
                    if(dp[j] + 1 < dp[i] && check(j + 1, i)) {
                        dp[i] = dp[j] + 1;
                        pre[i] = j;
                    }
                }
            }
            vector <int> d;
            d.push_back(n);
            int p = n;
            while(pre[p]) d.push_back(p = pre[p]);
            reverse(d.begin(), d.end());
            for(int i = 0; i < d.size(); i++) {
                int j = (i == 0 ? 0 : d[i - 1]);
                for(int k = j + 1; k <= d[i]; k++) {
                    cout << s[k];
                }
                if(i != d.size() - 1) cout << ' ';
            }
            cout << '
    ';
        }
        return 0;
    }
    
    

    B.Irreducible Polynomial

    结论题,分情况讨论一下即可。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 10 + 5, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
    const ll inf = 1000000000000000010LL;
    #define lson o<<1,l,m
    #define rson o<<1|1,m+1,r
    #define mid l + ((r-l)>>1)
     
    int kase, n, a[MAXN];
    int main() {
        ios::sync_with_stdio(false); cin.tie();
        cin >> kase;
        while (kase--) {
            cin >> n;
            for (int i = n; ~i; i--)cin >> a[i];
            if (n == 2) {
                ll x = (ll)a[1] * a[1] - 4LL * a[2] * a[0];
                if (x < 0)cout << "Yes
    ";
                else cout << "No
    ";
            }
            else if (n <= 1)cout << "Yes
    ";
            else cout << "No
    ";
        }
    }
    

    C.Governing sand

    枚举最终最大高度,然后贪心砍掉费用最小的树即可。
    首先会砍掉高度大于枚举值的树,之后根据数量在权值线段树中贪心找到答案。
    注意不同种类的树的高度可能相同。

    Code
    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 5;
    int n;
    struct node{
        int h, c;
        ll p, sum;
        bool operator < (const node &A)const {
            return h < A.h;
        }
    }a[N], b[N];
    ll sum[N];
    ll sz[200 << 2], sumv[200 << 2];
    void build(int o, int l, int r) {
        sz[o] = sumv[o] = 0;
        if(l == r) return;
        int mid = (l + r) >> 1;
        build(o << 1, l, mid);
        build(o << 1|1, mid + 1, r);
    }
    void update(int o, int l, int r, int p, int k) {
        sz[o] += k; sumv[o] += 1ll * p * k;
        if(l == r) return ;
        int mid = (l + r) >> 1;
        if(p <= mid) update(o << 1, l, mid, p, k);
        else update(o << 1|1, mid + 1, r, p, k);
    }
    ll query(int o, int l, int r, ll k) {
        if(l == r) return sumv[o] / sz[o] * k;
        int mid = (l + r) >> 1;
        if(sz[o << 1] >= k) return query(o << 1, l, mid, k);
        return sumv[o << 1] + query(o << 1|1, mid + 1, r, k - sz[o << 1]);
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        while(cin >> n) {
            for(int i = 1; i <= n; i++) {
                int h, c, p; cin >> h >> c >> p;
                a[i] = {h, c, p, 1ll * c * p};
            }
            sort(a + 1, a + n + 1);
            int tot = 0;
            for(int i = 1; i <= n; i++) {
                if(a[i].h != a[i - 1].h) b[++tot] = a[i];
                else b[tot].sum += a[i].sum, b[tot].p += a[i].p;
            }
            sum[tot + 1] = 0;
            for(int i = tot; i >= 1; i--) sum[i] = sum[i + 1] + b[i].sum;
            build(1, 1, 200);
            int j = 1;
            ll ans = INF, cur = 0;
            for(int i = 1; i <= tot; i++) {
                ll tmp = sum[i + 1];
                ll p = b[i].p;
                if(p > cur) {
                    ans = min(ans, tmp);
                } else {
                    ans = min(ans, tmp + query(1, 1, 200, cur - p + 1));
                }
                cur += b[i].p;
                while(j <= n && a[j].h == b[i].h) {
                    update(1, 1, 200, a[j].c, a[j].p);
                    j++;
                }
            }
            cout << ans << '
    ';
        }
        return 0;
    }
    
    

    D.Number

    签到题。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 10 + 5, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
    const ll inf = 1000000000000000010LL;
    #define lson o<<1,l,m
    #define rson o<<1|1,m+1,r
    #define mid l + ((r-l)>>1)
     
    int n, p;
    int get(int x) {
        int ans = 0;
        while (x) {
            x /= 10;
            ans++;
        }
        return ans;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie();
        cin >> n >> p;
        int m = get(p);
        if (n < m)cout << "T_T
    ";
        else {
            cout << p;
            for (int i = 1; i <= n - m; i++)cout << "0";
            cout << '
    ';
        }
        return 0;
    }
    

    E.Find the median

    题目中生成的区间可能会很大,考虑离散化,但是这样就会影响原来区间的信息。
    注意到有用的信息就是区间端点+覆盖次数。那么我们用线段树维护这些信息就行了。线段树中每个结点都维护的一个左闭右开的区间,另外有一些附加的信息,同时还保存每个叶子结点原来的大小(因为是离散化过后的)。
    然后就解决了。详见代码吧:

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 400005;
    ll a1, b1, c1, m1;
    ll a2, b2, c2, m2;
    int x[N], y[N], b[N << 1];
    int n, D;
    void Hash() {
        for(int i = 1; i <= n; i++) {
            x[i]++; y[i]++;
            if(x[i] > y[i]) swap(x[i], y[i]);
            b[++D] = x[i], b[++D] = y[i] + 1;
        }
        sort(b + 1, b + D + 1);
        D = unique(b + 1, b + D + 1) - b - 1;
    }
    ll sumv[N << 3], cntv[N << 3], lazy[N << 3];
    void build(int o, int l, int r) {
        sumv[o] = cntv[o] = lazy[o] = 0;
        if(l == r) return ;
        int mid = (l + r) >> 1;
        build(o << 1, l, mid);
        build(o << 1|1, mid + 1, r);
    }
    void push_down(int o, int l, int r) {
        if(lazy[o]) {
            int mid = (l + r) >> 1;
            lazy[o << 1] += lazy[o];
            cntv[o << 1] += lazy[o];
            sumv[o << 1] += lazy[o] * (b[mid + 1] - b[l]);
            lazy[o << 1|1] += lazy[o];
            cntv[o << 1|1] += lazy[o];
            sumv[o << 1|1] += lazy[o] * (b[r + 1] - b[mid + 1]);
            lazy[o] = 0;
        }
    }
    void push_up(int o) {
        sumv[o] = sumv[o << 1] + sumv[o << 1|1];
    }
    void update(int o, int l, int r, int L, int R) {
        if(L <= l && r <= R) {
            sumv[o] += b[r + 1] - b[l];
            cntv[o] += 1;
            lazy[o] += 1;
            return ;
        }
        push_down(o, l, r);
        int mid = (l + r) >> 1;
        if(L <= mid) update(o << 1, l, mid, L, R);
        if(R > mid) update(o << 1|1, mid + 1, r, L, R);
        push_up(o);
    }
    int query(int o, int l, int r, ll k) {
        if(l == r) return b[l] + ((k + cntv[o] - 1) / cntv[o]) - 1;
        push_down(o, l, r);
        int mid = (l + r) >> 1;
        if(sumv[o << 1] >= k) return query(o << 1, l, mid, k);
        else return query(o << 1|1, mid + 1, r, k - sumv[o << 1]);
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n;
        cin >> x[1] >> x[2] >> a1 >> b1 >> c1 >> m1;
        cin >> y[1] >> y[2] >> a2 >> b2 >> c2 >> m2;
        for(int i = 3; i <= n; i++) {
            x[i] = (a1 * x[i - 1] % m1 + b1 * x[i - 2] % m1 + c1) % m1;
            y[i] = (a2 * y[i - 1] % m2 + b2 * y[i - 2] % m2 + c2) % m2;
        }
        Hash();
        build(1, 1, D);
        ll sum = 0;
        for(int i = 1; i <= n; i++) {
            sum += y[i] - x[i] + 1;
            int L = lower_bound(b + 1, b + D + 1, x[i]) - b;
            int R = lower_bound(b + 1, b + D + 1, y[i] + 1) - b - 1;
            update(1, 1, D, L, R);
            cout << query(1, 1, D, (sum + 1) / 2) << '
    ';
        }
        return 0;
    }
    
    

    H.Pair

    数位(dp),加上限制:一个是数字本身的限制,另一个是是否满足题目条件的限制。
    对于(xor),要求(tleq x) (xor) (y),只要二进制高位一位满足,其余就可以随便取了;同理对于(x) (and) (y leq t),只要一位满足小于,后面的也可以随便取。
    注意一下(x,y)(0)的情况。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 32;
    int T;
    ll dp[N][2][2][2][2];
    int a, b, c;
    int na[N], nb[N], nc[N];
    ll dfs(int pos, int o1, int o2, int lim1, int lim2) {
        if(pos < 0) return 1;
        ll &t = dp[pos][o1][o2][lim1][lim2];
        if(t != -1) return t;
        int up1 = (o1 ? na[pos] : 1);
        int up2 = (o2 ? nb[pos] : 1);
        ll res = 0;
        for(int i = 0; i <= up1; i++) {
            for(int j = 0; j <= up2; j++) {
                int p = i & j;
                int q = i ^ j;
                if(lim1 && q < nc[pos]) continue;
                if(lim2 && p > nc[pos]) continue;
                res += dfs(pos - 1, o1 && (i == up1), o2 && (j == up2), lim1 && (q == nc[pos]), lim2 && (p == nc[pos]));
            }
        }
        return t = res;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            memset(dp, -1, sizeof(dp));
            cin >> a >> b >> c;
            for(int i = 31; i >= 0; i--) {
                na[i] = (a >> i & 1) ? 1 : 0;
                nb[i] = (b >> i & 1) ? 1 : 0;
                nc[i] = (c >> i & 1) ? 1 : 0;
            }
            ll ans = dfs(31, 1, 1, 1, 1);
            ans -= max(0, a - c + 1);
            ans -= max(0, b - c + 1);
            cout << (1ll * a * b) - ans << '
    ';
        }
        return 0;
    }
    
    

    J.A+B problem

    签到题。

    K.Function

    题意:
    (sum_{i=1}^nf(i)),其中,(f(i))为:

    [left{ egin{aligned} &3e+1,&i= p^e and p\%4=1\ &1,&else end{aligned} ight. ]

    思路:
    考虑(min25)筛求解。
    我们不管1,2的存在,最后加上其贡献即可。
    首先求出(g_1,g_2),分别质数表示(\% 4)为1和3的情况总数,然后一个一个来筛。筛的时候要同时考虑当前质数模4的情况以及对(g_1,g_2)的影响,它们都会减去某个值。
    然后就直接求和就行了,基本都是套用板子。
    最主要的还是求(g)的思路。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e6 + 5;
    int T;
    ll n;
    ll sum1[N], sum2[N], prime[N];
    ll w[N], ind1[N], ind2[N];
    ll g1[N], g2[N];
    bool chk[N];
    int tot, cnt;
    void pre(int n) { //  sqrt
        chk[1] = 1;
        for(int i = 1; i <= n; i++) {
            if(!chk[i]) {
                prime[++tot] = i;
                sum1[tot] = sum1[tot - 1];
                sum2[tot] = sum2[tot - 1];
                if(i % 4 == 1) ++sum1[tot];
                if(i % 4 == 3) ++sum2[tot];
            }
            for(int j = 1; j <= tot && prime[j] * i <= n; j++) {
                chk[i * prime[j]] = 1;
                if(i % prime[j] == 0) break;
            }
        }
    }
    void calc_g() {
        int z = sqrt(n);
        for(ll i = 1, j; i <= n; i = j + 1) {
            j = n / (n / i);
            w[++cnt] = n / i;
            g1[cnt] = w[cnt] / 4 + (w[cnt] % 4 >= 1) - 1;
            g2[cnt] = w[cnt] / 4 + (w[cnt] % 4 >= 3);
            if(n / i <= z) ind1[n / i] = cnt;
            else ind2[n / (n / i)] = cnt;
        }
        for(int i = 1; i <= tot; i++) {
            for(int j = 1; j <= cnt && prime[i] * prime[i] <= w[j]; j++) {
                ll tmp = w[j] / prime[i], k;
                if(tmp <= z) k = ind1[tmp]; else k = ind2[n / tmp];
                if(prime[i] % 4 == 1) {
                    g1[j] -= (g1[k] - sum1[i - 1]);
                    g2[j] -= (g2[k] - sum2[i - 1]);
                } else if(prime[i] % 4 == 3) {
                    g1[j] -= (g2[k] - sum2[i - 1]);
                    g2[j] -= (g1[k] - sum1[i - 1]);
                }
            }
        }
    }
    int f(int p, int q) {
        if(p % 4 == 1) return 3 * q + 1;
        return 1;
    }
    ll S(ll x, int y) { // 2~x >= P_y
        if(x <= 1 || prime[y] > x) return 0;
        ll z = sqrt(n);
        ll k = x <= z ? ind1[x] : ind2[n / x];
        ll ans = 4 * g1[k] - 4 * sum1[y - 1] + g2[k] - sum2[y - 1];
        if(y == 1) ans++;
        for(int i = y; i <= tot && prime[i] * prime[i] <= x ; i++) {
            ll pe = prime[i], pe2 = prime[i] * prime[i];
            for(int e = 1; pe2 <= x; ++e, pe = pe2, pe2 *= prime[i]) {
                ans += f(prime[i], e) * S(x / pe, i + 1) + f(prime[i], e + 1);
            }
        }
        return ans;
    }
    int main() {
        freopen("input.in", "r", stdin);
        cin >> T;
        while(T--) {
            memset(chk, 0, sizeof(chk)); tot = cnt = 0;
            cin >> n;
            int tmp = sqrt(n);
            pre(tmp);
            calc_g();
            cout << S(n, 1) + 1 << '
    ';
        }
        return 0;
    }
    
    
  • 相关阅读:
    bzoj 2763: [JLOI2011]飞行路线
    2008年NOI全国竞赛 假面舞会
    八数码(双向宽搜)
    poj 1988 Cube Stacking && codevs 1540 银河英雄传说(加权并茶几)
    codevs 3693 数三角形
    bzoj 3831 Little Bird (单调队列优化dp)
    hdu 3530 Subsequence
    poj 2823 Sliding Window(单调队列)
    线段树各种小练习
    codevs 2449 骑士精神 (IDDfs)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11332790.html
Copyright © 2011-2022 走看看