20200405题解

第一题:水题

#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\n", 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\n", 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

猜你喜欢

转载自www.cnblogs.com/PHDHD/p/12637616.html
今日推荐