zoukankan      html  css  js  c++  java
  • 20200405~06题解

    Day1:

    第一题:水题

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 1005;
    char s1[MAXN], s2[MAXN]; 
    
    inline int ord(char c){
        if(c >= 'a' && c <= 'z') return c - 'a';
        return c - 'A';
    }
    
    int main(){
        scanf("%s%s", s1, s2);
        int len1 = strlen(s1), len2 = strlen(s2);
        for(int i=0, j=0; i<len2; i++, j=(j+1)%len1)
            putchar((26 + ord(s2[i]) - ord(s1[j])) % 26 + ((s2[i] >= 'a') ? 'a' : 'A'));
        return 0;
    }
    View Code

    第二题:贪心提前处理出最后的序列(以$a*b$为关键字排序),最后高精度模拟即可

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 1005;
    struct Node{
        int a, b;
        const bool operator < (const Node &x) const{
            return a * b < x.a * x.b;
        }
    }a[MAXN];
    
    const int BITLEN = 10000, BIGSIZE = 900;
    struct Big{
        int val[BIGSIZE+1];
        void operator = (int x){
            memset(val, 0, sizeof(val));
            val[0] = x;
        }
        Big(int x = 0){this->operator = (x);}
        Big operator + (Big x){
            Big ans;
            for(int i=0; i<BIGSIZE; i++){
                ans.val[i] += val[i] + x.val[i];
                ans.val[i + 1] += ans.val[i] / BITLEN;
                ans.val[i] %= BITLEN;
            }
            return ans;
        }
        Big operator * (int x){
            Big ans;
            for(int i=0; i<BIGSIZE; i++)
                ans.val[i] = x * val[i];
            for(int i=0; i<BIGSIZE-1; i++)
                ans.val[i+1] += ans.val[i] / BITLEN, ans.val[i] %= BITLEN;
            return ans;
        }
        Big operator / (int x){
            Big ans;
            for(int i=BIGSIZE-1, rest=0; i>=0; i--){
                rest = rest * BITLEN + val[i];
                ans.val[i] = rest / x;
                rest = rest % x;
            }
            return ans;
        }
        const bool operator < (const Big &x)const{
            for(int i=BIGSIZE-1; i>=0; i--)
                if(val[i] != x.val[i]) return val[i] < x.val[i];
            return false;
        }
        void print(){
            int len = BIGSIZE - 1;
            while(!val[len]) len--;
            for(int i=len; i>=0; i--){
                if(i != len)
                    for(int j=BITLEN/10; j>1; j/=10)
                        if(val[i] < j)
                            putchar('0');
                printf("%d", val[i]);
            }
        }
    };
    
    int main(){
        int n = read();
        for(int i=0; i<=n; i++)
            a[i].a = read(), a[i].b = read();
        sort(a+1, a+1+n);
        Big ans = 0, sum = a[0].a;
        for(int i=1; i<=n; i++){
            Big temp = sum / a[i].b;
            if(ans < temp) ans = temp;
            sum = sum * a[i].a;
        }
        ans.print();
        return 0;
    }
    View Code

    第三题:倍增Dp提前预处理出一个点走$2^i$后的情况,对于寻找第一近和第二近的房子可以用map进行维护,每次找到最近的几个点,最后直接模拟即可

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <cmath>
    #include <queue>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 100001, LOGN = 18;
    int h[MAXN], next1[MAXN], next2[MAXN];
    long long Dp[MAXN][LOGN+1][2], last[MAXN][LOGN+1];
    map<int,int> hash;
    
    struct Tuple{
        int dis, h, id;
        const bool operator < (const Tuple &x) const{
            if(dis != x.dis) return dis > x.dis;
            return h > x.h;
        }
    };
    
    priority_queue<Tuple> Q;
    
    int main(){
        int n = read();
        for(int i=1; i<=n; i++)
            h[i] = read();
        hash[h[n]] = n, hash[h[n-1]] = n - 1;
        next1[n] = next2[n] = n, next1[n-1] = n, next2[n-1] = n-1;
        for(int i=n-2; i>=1; i--){
            map<int,int>::iterator it = hash.upper_bound(h[i]), it2 = it;
            for(int j=1; j<=2; j++, it++) if(it != hash.end())
                Q.push((Tuple){abs(h[i]-it->first), it->first, it->second});
            if(it2 != hash.begin()){
                it2--;
                for(int j=1; j<=2; j++, it2--){
                    Q.push((Tuple){abs(h[i]-it2->first), it2->first, it2->second});
                    if(it2 == hash.begin()) break;
                }
            }
            next1[i] = Q.top().id;
            Q.pop();
            next2[i] = Q.top().id;
            hash[h[i]] = i;
            while(!Q.empty()) Q.pop();
        }
        for(int i=1; i<=n; i++)
            Dp[i][0][0] = abs(h[next2[i]] - h[i]), Dp[i][0][1] = abs(h[next1[i]] - h[i]);
        for(int i=1; i<=n; i++)
            Dp[i][1][0] = Dp[i][0][0], Dp[i][1][1] = (next2[i] == i) ? 0 : Dp[next2[i]][0][1], last[i][1] = (next2[i] == i) ? next2[i] : next1[next2[i]];
        for(int i=2; i<=LOGN; i++) for(int j=1; j<=n; j++){
            Dp[j][i][0] = Dp[last[j][i-1]][i-1][0] + Dp[j][i-1][0], Dp[j][i][1] = Dp[last[j][i-1]][i-1][1] + Dp[j][i-1][1];
            last[j][i] = last[last[j][i-1]][i-1];
        }
        int x0 = read(), s0 = 0;
        double maxNum = 1e18;
        for(int i=1; i<=n; i++){
            long long disA = 0, disB = 0, u = i, x = x0;
            for(int j=LOGN; j>=1; j--) if(Dp[u][j][0] + Dp[u][j][1] <= x)
                disA += Dp[u][j][0], disB += Dp[u][j][1], x -= Dp[u][j][0] + Dp[u][j][1], u = last[u][j];
            if(Dp[u][0][0] <= x) disA += Dp[u][0][0];
            if((double)disA / disB < maxNum) maxNum = (double)disA / disB, s0 = i;
        }
        printf("%d
    ", s0);
        int m = read();
        for(int i=1; i<=m; i++){
            long long disA = 0, disB = 0, u = read(), x = read();
            for(int j=LOGN; j>=1; j--) if(Dp[u][j][0] + Dp[u][j][1] <= x)
                disA += Dp[u][j][0], disB += Dp[u][j][1], x -= Dp[u][j][0] + Dp[u][j][1], u = last[u][j];
            if(Dp[u][0][0] <= x) disA += Dp[u][0][0];
            printf("%lld %lld
    ", disA, disB);
        }
        return 0;
    }
    View Code

    第四题:对于$n<=1000$,暴力即可,对于$n<=10^6,z=0$,使用树状数组优化即可,对于数据加强的$11,12$点,可以考虑用树套树,但也可以用CDQ

    因为CDQ的前提必须是更新过的节点不再更新,所以先分治,后计算左对右贡献的做法显然不行,但是可以先分治左,再计算左对右,再计算右,需要时刻牢记自己定义的CDQ是什么

    这道题CDQ函数定义:将L到R的已经对X排序的数组计算贡献,并最后按照Y进行排序。

    这样如果数组顺序不对需要重新排序(用sort排序),当然因为sort是在第一层CDQ里面的所以总时间复杂度还是$O(nlog^2n)$,和树套树的时间复杂度一样(虽然常数大了一点)

    普通代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 1000001;
    struct Tuple{
        int x, y, z, val;
        bool const operator < (const Tuple &temp) const{
            if(x != temp.x) return x < temp.x;
            if(y != temp.y) return y < temp.y;
            return z < temp.z;
        }
    }tup[MAXN];
    
    struct BIT{
        int val[MAXN];
        void add(int pos,int x){
            for(int i=pos; i<MAXN; i+=i&(-i))
                val[i] = max(val[i], x);
        }
        int query(int pos){
            int ans = 0;
            for(int i=pos; i; i-=i&(-i))
                ans = max(ans, val[i]);
            return ans;
        }
    }bit;
    
    int main(){
        int n = read();
        for(int i=1; i<=n; i++)
            tup[i].x = read(), tup[i].y = read(), tup[i].z = read(), tup[i].val = 1;
        sort(tup+1, tup+1+n);
        if(n > 10001){
            for(int i=1; i<=n; i++){
                tup[i].val = bit.query(tup[i].y) + 1;
                bit.add(tup[i].y, tup[i].val);
            }
        }
        else{
            for(int i=1; i<=n; i++) for(int j=1; j<i; j++)
                if(tup[j].y <= tup[i].y && tup[j].z <= tup[i].z)
                    tup[i].val = max(tup[i].val, tup[j].val + 1);
        }
        int ans = 0;
        for(int i=1; i<=n; i++)
            ans = max(ans, tup[i].val);
        printf("%d", ans);
        return 0;
    }
    View Code

    数据加强版代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 1000005;
    struct Tuple{
        int x, y, z, val;
        bool const operator < (const Tuple &temp) const{
            if(x != temp.x) return x < temp.x;
            if(y != temp.y) return y < temp.y;
            return z < temp.z;
        }
    }tup[MAXN], temp[MAXN];
    
    struct BIT{
        int val[MAXN];
        void add(int pos,int x){
            for(int i=pos; i<MAXN; i+=i&(-i))
                val[i] = max(val[i], x);
        }
        int query(int pos){
            int ans = 0;
            for(int i=pos; i; i-=i&(-i))
                ans = max(ans, val[i]);
            return ans;
        }
        void clear(int pos){
            for(int i=pos; i<MAXN; i+=i&(-i))
                val[i] = 0;
        }
    }bit;
    
    const bool cmp(const Tuple &a,const Tuple &b){
        if(a.y != b.y) return a.y < b.y;
        return a.z < b.z;
    }
    
    void CDQ(int l,int r){
        int mid = (l + r) >> 1;
        if(l == r) return;
        CDQ(l, mid);
        sort(tup+mid+1, tup+r+1, cmp);
        for(int i=l, j=mid+1, k=l; k<=r; k++){
            if(j > r || (i <= mid && tup[i].y <= tup[j].y))
                bit.add(tup[i].z, tup[i].val), i++;
            else tup[j].val = max(tup[j].val, bit.query(tup[j].z) + 1), j++;
        }
        for(int i=l; i<=mid; i++)
            bit.clear(tup[i].z);
        sort(tup+mid+1, tup+r+1);
        CDQ(mid+1, r);
        for(int i=l, j=mid+1, k=l; k<=r; k++){
            if(j > r || (i <= mid && tup[i].y <= tup[j].y))
                temp[k] = tup[i++];
            else temp[k] = tup[j++];
        }
        for(int i=l; i<=r; i++)
            tup[i] = temp[i];
    }
    
    int main(){
        int n = read();
        for(int i=1; i<=n; i++)
            tup[i].x = read() + 1, tup[i].y = read() + 1, tup[i].z = read() + 1, tup[i].val = 1;
        sort(tup+1, tup+1+n);
        CDQ(1, n);
        int ans = 0;
        for(int i=1; i<=n; i++)
            ans = max(ans, tup[i].val);
        printf("%d", ans);
        return 0;
    }
    View Code

     Day2:

    第一题:数论水题,恰好用上了我改进版的扩展欧几里得函数

    第二题:线段树区间修改,区间查询的题目,当然也可以用前缀数组加上二分答案来做

    线段树代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 1000005;
    
    int val[MAXN];
    
    struct Segment{
        struct Node{
            int l, r, isSigned, sign, minNum;
        }node[MAXN*4];
        inline void mix(int x,int sign){
            node[x].sign += sign;
            node[x].minNum += sign;
            node[x].isSigned = true;
        }
        void spread(int x){
            if(node[x].isSigned){
                mix(x*2, node[x].sign);
                mix(x*2+1, node[x].sign);
                node[x].sign = 0;
                node[x].isSigned = false;
            }
        }
        bool change(int l,int r,int sign,int x = 1){
            if(l <= node[x].l && node[x].r <= r){
                mix(x, sign);
                return node[x].minNum >= 0;
            }
            spread(x);
            bool flag = true;
            if(node[x*2].r >= l) flag &= change(l, r, sign, x*2);
            if(node[x*2+1].l <= r) flag &= change(l, r, sign, x*2+1);
            node[x].minNum = min(node[x*2].minNum, node[x*2+1].minNum);
            return flag;
        }
        void build(int l,int r,int x = 1){
            node[x].l = l, node[x].r = r;
            if(l == r){
                node[x].minNum = node[x].sign = val[l];
                return;
            }
            int mid = (l + r) >> 1;
            build(l, mid, x*2);
            build(mid+1, r, x*2+1);
            node[x].minNum = min(node[x*2].minNum, node[x*2+1].minNum);
        }
    }T;
    
    int main(){
        int n = read(), m = read();
        for(int i=1; i<=n; i++)
            val[i] = read();
        T.build(1, n);
        for(int i=1; i<=m; i++){
            int v = read(), l = read(), r = read();
            if(!T.change(l, r, -v)){
                printf("-1
    %d", i);
                return 0;
            }
        }
        printf("0");
        return 0;
    }
    View Code

    前缀数组二分答案做法:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 1000005;
    long long val[MAXN], temp[MAXN];
    int Qv[MAXN], Ql[MAXN], Qr[MAXN];
    
    int main(){
        int n = read(), m = read();
        for(int i=1; i<=n; i++)
            val[i] = read();
        for(int i=1; i<=m; i++)
            Qv[i] = read(), Ql[i] = read(), Qr[i] = read();
        int l = 1, r = m + 1;
        while(l < r){
            int mid = (l + r) >> 1;
            for(int i=1; i<=n; i++)
                temp[i] = val[i];
            for(int i=n; i>=2; i--)
                temp[i] -= temp[i-1];
            for(int i=1; i<=mid; i++)
                temp[Ql[i]] += -Qv[i], temp[Qr[i] + 1] -= -Qv[i];
            for(int i=2; i<=n; i++)
                temp[i] += temp[i-1];
            bool flag = true;
            for(int i=1; i<=n; i++)
                flag &= (temp[i] >= 0);
            if(flag) l = mid + 1;
            else r = mid;
        }
        if(l == m + 1) printf("0");
        else printf("-1
    %d", l);
        return 0;
    }
    View Code

    第三题:图论题,首先使用倍增优化优化提点的过程,之后考虑贪心,二分答案,对答案$mid$

    将所有的军队分为三类:

    1.不能走到1节点,那就尽可能向上走

    2.能走到1节点但不能走回来,这样如果这个子节点需要军队驻扎就驻扎在这里,否则就走到1节点

    3.能走到1节点,还能走回来,这种军队就走到1节点

    最后再对没走到的子节点进行分配即可

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 50001, LOGN = 16;
    int head[MAXN], next[MAXN<<1], last[MAXN<<1], val[MAXN<<1], lineNum = 0;
    void add(int x,int y,int v){
        lineNum++, next[lineNum] = head[x], last[lineNum] = y, val[lineNum] = v, head[x] = lineNum;
    }
    
    long long Dp[MAXN][LOGN+1], fa[MAXN][LOGN+1];
    int pos[MAXN], n, m, cnt = 0;
    pair<long long,int> temp[MAXN], need[MAXN];
    bool isRest[MAXN], isNeed[MAXN];
    
    void DFS(int x,int pre){
        for(int i=1; i<=LOGN; i++)
            Dp[x][i] = Dp[fa[x][i-1]][i-1] + Dp[x][i-1], fa[x][i] = fa[fa[x][i-1]][i-1];
        for(int l=head[x]; l; l=next[l]){
            int y = last[l];
            if(y != pre)
                Dp[y][0] = val[l], fa[y][0] = x, DFS(y, x);
        }
    }
    
    bool BFS(int x,int pre){
        bool isSon = true, flag = false;
        for(int l=head[x]; l; l=next[l]){
            int y = last[l];
            if(y == pre) continue;
            isSon = false, BFS(y, x);
            flag |= isNeed[y];
        }
        if(!isSon) isNeed[x] &= flag;
    }
    
    bool check(long long mid){
        memset(isNeed, true, sizeof(isNeed));
        memset(isRest, false, sizeof(isRest));
        for(int i=1; i<=m; i++)
            temp[i] = make_pair(mid, pos[i]);
        for(int i=1; i<=m; i++) for(int j=LOGN; j>=0; j--)
            if(fa[temp[i].second][j] != 1 && temp[i].first >= Dp[temp[i].second][j])
                temp[i].first -= Dp[temp[i].second][j], temp[i].second = fa[temp[i].second][j];
        int cntRest = m, cntLast = 0;
        for(int i=1; i<=m; i++)
            if(temp[i].first < Dp[temp[i].second][0])
                temp[i].first = 1e18, cntRest--, isNeed[temp[i].second] = false;
        for(int i=1; i<=cnt; i++) BFS(need[i].second, 1);
        cntLast = cntRest;
        sort(temp+1, temp+1+m);
        for(int i=1; i<=cntRest; i++)
            if(temp[i].first < 2 * Dp[temp[i].second][0] && isNeed[temp[i].second])
                temp[i].first = 1e18, cntLast--, isNeed[temp[i].second] = false;
            else temp[i].first -= Dp[temp[i].second][0];
        sort(temp+1, temp+1+cntRest);
        cntRest = cntLast;
        int i = 1, j = 1;
        while(1){
            while(!isNeed[need[j].second] && j<=cnt) j++;
            if(j > cnt) return true;
            if(i > cntRest) return false;
            if(temp[i].first < need[j].first) i++;
            else i++, j++;
        }
    }
    
    int main(){
        n = read();
        long long l = 0, r = 0;
        for(int i=1; i<n; i++){
            int x = read(), y = read(), v = read();
            add(x, y, v), add(y, x, v), r += v;
        }
        for(int i=0; i<=LOGN; i++) fa[1][i] = 1;
        DFS(1, 1);
        for(int i=2; i<=n; i++) if(fa[i][0] == 1)
            need[++cnt] = make_pair(Dp[i][0], i);
        sort(need+1, need+1+cnt);
        m = read();
        for(int i=1; i<=m; i++)
            pos[i] = read();
        bool flag = false;
        while(l < r){
            int mid = (l + r) >> 1;
            if(check(mid)) r = mid, flag = true;
            else l = mid + 1;
        }
        if(flag) printf("%d", l);
        else printf("-1");
        return 0;
    }
    View Code
  • 相关阅读:
    Linux企业运维人员最常用150个命令汇总
    【ASP.NET Core快速入门】(七)WebHost的配置、 IHostEnvironment和 IApplicationLifetime介绍、dotnet watch run 和attach到进程调试
    C#7.0新特性
    【转载】ASP.NET Core 依赖注入
    【ASP.NET Core快速入门】(六)配置的热更新、配置的框架设计
    【ASP.NET Core快速入门】(五)命令行配置、Json文件配置、Bind读取配置到C#实例、在Core Mvc中使用Options
    【ASP.NET Core快速入门】(四)在CentOS上安装.NET Core运行时、部署到CentOS
    Linux命令收集
    【ASP.NET Core快速入门】(二)部署到IIS
    【ASP.NET Core快速入门】(一)环境安装
  • 原文地址:https://www.cnblogs.com/PHDHD/p/12637616.html
Copyright © 2011-2022 走看看