2018CCPC湘潭邀请赛部分题解

A.Easy h h h-index

  • 解题思路

    找到一个h,使得h最大且有h个大于等于h的。那么我们必然可以利用后缀和,枚举最优的 h h h

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 2e5 + 10;
int n;
ll a[N];
void solve(){
    //找到一个h,使得h最大且有h个大于等于h的。
    ll maxx = min(a[n],1LL * n);
    for(int i = n - 1; i >= 0; -- i){
        a[i] += a[i + 1];
        maxx = max(maxx,min(a[i],1LL * i));
    }
    printf("%lld\n", maxx);
}
int main(){
    while(~scanf("%d", &n)){
        for(int i = 0; i <= n; ++ i){
            scanf("%lld", &a[i]);
        }
        solve();
    }
    return 0;
}

B.Subsequence

  • 解题思路

    单调队列(不会的可以自己去学一下,这个数据结构特别有用)。我们暴力肯定行不通,那么我们得想一种 O ( n ) O(n) O(n)的解决方法,即单调队列,我们维护一个单调递增和一个单调递减队列,那么队头和队尾即是当前这段区间的最小值和最大值,遍历过去取最优即可。

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e5 + 10;
int n,m,k;
int a[N];
int q1[N],s1,e1;//单调递减队列。
int q2[N],s2,e2;//单调递增队列。
void solve(){
    int maxx = 0,pos = 0;
    s1 = 0,e1 = 0,s2 = 0,e2 = 0;
    for(int i = 1; i <= n; ++ i){
        //注意这里可以相等。
        while(s1 < e1 && a[q1[e1 - 1]] < a[i])e1 --;//维护单调递减队列。
        while(s2 < e2 && a[q2[e2 - 1]] > a[i])e2 --;//维护单调递增队列。
        q1[e1 ++] = i;
        q2[e2 ++] = i;
        //维护题目要求,满足区间[m,k]
        while(s1 < e1 && s2 < e2 && a[q1[s1]] - a[q2[s2]] > k){
            //判断两者哪个下标更前,剔除。
            if(q1[s1] < q2[s2]){
                pos = q1[s1 ++];
            }
            else{
                pos = q2[s2 ++];
            }
        }
        if(s1 < e1 && s2 < e2 && a[q1[s1]] - a[q2[s2]] >= m){
            maxx = max(maxx,i - pos);
        }
    }
    printf("%d\n", maxx);
}
int main(){
    while(~scanf("%d%d%d", &n, &m, &k)){
        for(int i = 1; i <= n; ++ i){
            scanf("%d", &a[i]);
        }
        solve();
    }
    return 0;
}

C.Sorting

  • 解题思路

    我们将公式转化一下,即同时取倒数。这样可得: c p i − 1 a p i − 1 + b p i − 1 ≥ c p i a p i + b p i \frac{c_{p_{i-1}}}{a_{p_{i-1}}+b_{p_{i-1}}}\geq\frac{c_{p_{i}}}{a_{p_{i}}+b_{p_{i}}} api1+bpi1cpi1api+bpicpi​,这样,我们就可以进行自定义排序了,注意我们要避免除法导致精度损失,即交叉相乘比较。由于数据最值为 2 e 9 2e9 2e9,所以最大为 2 e 9 × 4 e 9 = 8 e 18 2e9\times 4e9=8e18 2e9×4e9=8e18​​,这个我们需要适用 u n s i g n e d   l o n g   l o n g unsigned \ long \ long unsigned long long来实现。​

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

typedef unsigned long long ll;
const int N = 1000 + 10;
int n;
struct node{
    ll a,b,c;
    int id;
    bool operator < (const node &A){
        ll temp1 = c * (A.a + A.b);
        ll temp2 = A.c * (a + b);
        if(temp1 == temp2){
            return id < A.id;
        }
        return temp1 > temp2;
    }
}nums[N];
void solve(){
    sort(nums + 1,nums + 1 + n);
    for(int i = 1; i <= n; ++ i){
        printf("%d%c", nums[i].id, i == n ? '\n' : ' ');
    }
}
int main(){
    while(~scanf("%d", &n)){
        for(int i = 1; i <= n; ++ i){
            scanf("%lld%lld%lld", &nums[i].a, &nums[i].b, &nums[i].c);
            nums[i].id = i;
        }
        solve();
    }
    return 0;
}

D.String Transformation

  • 解题思路

    由于可以通过增删aa,bb,abab,所以 a b − > a a b a b b − > b a ab->aababb->ba ab>aababb>ba, b a − > a a b a b b − > a b ba->aababb->ab ba>aababb>ab,即说明 a b , b a ab,ba ab,ba​​​​可以相互转化,同时,我们的每次操作都只能更改偶数个字母。同时我们又知道,c我们是不能更改的,所以实际上我们只需要判断c分隔的每一段a,b字符数量的奇偶性是不是相同的。

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

string s1,s2;
vector<pair<int,int> > cal(string s){
    vector<pair<int,int> > v;
    pair<int,int> temp;
    for(int i = 0; i <= s.size(); ++ i){
        if(s[i] == 'c' || i == s.size()){
            temp.first = temp.first & 1;
            temp.second = temp.second & 1;
            v.push_back(temp);
            temp.first = 0,temp.second = 0;
        }
        else{
            if(s[i] == 'a')temp.first ++;
            if(s[i] == 'b')temp.second ++;
        }
    }
    return v;
}
void solve(){
}
int main(){
    while(cin >> s1 >> s2){
        if(cal(s1) == cal(s2)){
            cout << "Yes" << endl;
        }
        else{
            cout << "No" << endl;
        }
    }
    return 0;
}

E.2018

  • 解题思路

    题目所求为 x ∈ [ a , b ] , y ∈ [ c , d ] x\in[a,b],y\in[c,d] x[a,b],y[c,d]满足 ( x y ) m o d    2018 = 0 (xy)\mod 2018 =0 (xy)mod2018=0的数量对。即说明 x , y x,y x,y 2018 2018 2018的因子,而其因子只有 1 , 2 , 1009 , 2018 1,2,1009,2018 1,2,1009,2018。那么我们发现 2018 2018 2018可以和所有的数相匹配,偶数可以和所有的 1009 1009 1009匹配。这样处理注意去掉重复计算的即可。

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
int a,b,c,d;
int cal(int a,int b,int v){
    //统计区间[a,b]内v的因子个数。
    return b / v - (a - 1) / v;
}
void solve(){
    //为了避免重复
    ll s1 = cal(a,b,2), s2 = cal(a,b,1009), s3 = cal(a,b,2018);
    ll b1 = cal(c,d,2), b2 = cal(c,d,1009), b3 = cal(c,d,2018);
    ll F = (s2-s3)*b1; //左边1009奇数倍的个数乘以右边偶数个数
    ll U = s3*(d-c+1); //左边2018的倍数的个数乘以右边的所有的数
    ll C = (b2-b3)*(s1-s3); //右边1009奇数倍的个数乘以左边偶数的个数(因为2018的倍数同样是偶数,在U里面已经计算过,所以要减去)
    ll K = b3*(b-a+1-s2); //右边2018的倍数的个数乘以左边所有的数(同样要减去已经计算过的1009奇数倍的个数)
    cout<<F+U+C+K<<endl;
}
int main(){
    while(cin >> a >> b >> c >> d){
        solve();
    }
    return 0;
}
posted @   unique_pursuit  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示