codeforces#702 全部题解

太久没打cf了,赛时只做出来3道QAQ,读题和手速现在慢的离谱,只能靠赛后补题来弥补了......

 

A. Dense Array

数据很小直接模拟插入即可,x = min(a[i],a[i+1])   y = min(a[i],a[i+1])

如果 y >= 2 * x , 不需要操作

否则不断插入 2 * x 直到满足条件,最后统计一下插入2x 的数量即可

 

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int t,n,m;
int a[104];
#define sz std::ios::sync_with_stdio(false) 
int main()
{
    sz;
    cin >> t;
    while(t--){
        int cnt = 0;
        cin >> n;
        for(int i = 1; i <= n; i++){
            cin >> a[i];
        }
        for(int i = 1; i < n; i++){
            int k = 1;
            int minn = min(a[i+1],a[i]);
            int maxx = max(a[i+1],a[i]);
            if(maxx <= 2 * minn){
                continue;
            }
            else{
                while(maxx > 2 * minn){
                    minn *= 2;
                    cnt++;
                }
            }
        }
        cout << cnt << endl;
    }
}

 

 

B. Balanced Remainders

记录一下数列中除3余1,2,0 的个数,由题意可知,每次操作有以下结果:余0->余1 余1->余2 余2->余0

为了使其都变成n/3,我们可以从前往后推下去,增加个数向前一个数借,减少个数给下一位,模拟这一过程直到每个数都为n/3即可

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int t,n,m;
int a[104];
int c[5];
#define sz std::ios::sync_with_stdio(false)
int main()
{
    sz;
    cin >> t;
    while(t--){
        int ans = 0;
        cin >> n;
        memset(c,0,sizeof(c));
        for(int i = 0; i < n; i++){
            int x;
            cin >> x;
            c[x % 3]++;
        }
        int m = n / 3;
        for(int i = 0; i < 3; i++){
            if(c[i] > m){
                if(i == 2){
                    c[0] += c[i]-m;
                }
                else{
                    c[i+1] += c[i]-m;
                }
                ans += c[i]-m;
                c[i] = m;
            }
            else if(c[i] < m){
                if(i == 0){
                    c[2] -= (m - c[i]);
                }
                else{
                    c[i - 1] -= (m - c[i]);
                }
                
                ans += (m - c[i]);
                c[i] = m;
            }
        }
        cout << ans << endl;
    }

}

C. Sum of Cubes

 数据大小为1e12,那么立方数最大为1e4,可以先预处理用数组存储一下1e4个立方数,之后就枚举数组的每个数,二分查找判断其相减得到的另一个数是否为立方数。

 

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int t,n,m;
ll x;
ll a[10004];
int tt;
bool c[10004];
#define sz std::ios::sync_with_stdio(false)
void unit(){
    
    for(ll i = 1; i <= 10000; i++){
        a[++tt] = i * i * i;
    }
}
int main()
{
    unit();
    cin >> t;
    while(t--){
        cin >> x;
        bool judge = 0;
        for(int i = 1; i <= tt; i++){
            ll xx = a[i];
            ll yy = x - xx;
            if(yy <= 0){
                break;
            }
            ll pos = lower_bound(a+1,a+1+tt,yy) - a;
            if(a[pos] == yy){
                judge = 1;
                break;
            }
        }
        if(judge) cout << "YES\n";
        else cout << "NO\n";
    }
}

 

D. Permutation Transformation

模拟建树,用in数组记录每个元素对应下标,查找区间最大值可以用线段树logn查找maxn,然后利用in数组通过maxn找到其对应的下标,以该下标为父节点递归建左子树右子树。

#include<iostream>
using namespace std;
int tt,n,m;
struct Hi{
    int maxx;
    int l,r;
}t[1000000];
int a[1000005];
int ans[1000004];
int in[100006];
// int a[] = {3,5,8,1,4,2};
void built(int i,int l,int r){
    t[i].l = l;
    t[i].r = r;
    if(l == r){
        t[i].maxx = a[l];
        return;
    }
    int mid = (l + r) / 2;
    built(i * 2,l,mid);
    built(i * 2 + 1,mid + 1,r);
    t[i].maxx = max(t[i * 2].maxx,t[i * 2 + 1].maxx);
}
int findmax(int i,int l,int r,int ll,int rr)
{
    if(ll <= l && rr >= r) return t[i].maxx;
    else if(ll > r || rr < l) return 0;
    else{
        int mid = (l + r) / 2;
        return max(findmax(i * 2,l,mid,ll,rr), findmax(i * 2 + 1,mid+1,r,ll,rr));
    }
}
void work(int dep,int l,int r)
{
    int num = findmax(1,0,n-1,l,r);
    ans[in[num]] = dep;
    if(l < in[num]) work(dep+1,l,in[num] - 1);
    if(in[num] + 1 <= r) work(dep+1,in[num] + 1,r);
}
int main()
{
    
    cin >> tt;
    while(tt--){
        cin >> n;
        for(int i = 0; i < n; i++){
            cin >> a[i];
            in[a[i]] = i;
        }
        built(1,0,n-1);
        work(0,0,n-1);
        for(int i = 0; i < n; i++){
            cout << ans[i] << " ";
        }
        cout << "\n";
    }   
}

E. Accidental Victory 

先对所有人按照货币升序进行排序得到数组a,再对排序后的数组进行前缀和得到数组f。

此时f[i]可以看做第i人能获得的最大货币(即赢了前面所有人),让其与a[i+1]进行比较大小,如果比a[i+1]大,那么他可以继续成为赢家,货币总值变为f[i+1],如此看来某个人为了成为最后赢家,其前缀和要每次都比下一个人的货币多,因此我们可以从货币量最多的人开始向前判断,遇到第一个不能向后扩展的人结束,途径的人都可以成为赢家。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
int t,n,m;
ll x;
struct Hi{
    ll num;
    ll id;
}a[2000004];
ll f[200005];
vector<int>v;
map<int,int>mm;
#define sz std::ios::sync_with_stdio(false)int cmp(Hi A,Hi B){
    return A.num < B.num;
}
int main()
{
    sz;
    cin >> t;
    while(t--){
        mm.clear();
        cin >> n;
        // v.clear();
        for(int i = 1; i <= n; i++){
            cin >> a[i].num;
            a[i].id = i;
        }
        sort(a+1,a+1+n,cmp);
        for(int i = 1; i <= n; i++){
            f[i] = f[i-1] + a[i].num;
        }
        ll ans = 1;
        mm[a[n].id] = 1;
        for(int i = n - 1; i >= 1; i--){
            if(f[i] >= a[i+1].num){
                ans++;
                // v.push_back(a[i].id);
                mm[a[i].id] = 1;
            }
            else{
                break;
            }
        }
        cout << ans << "\n";
        for(int i = 1; i <= n; i++){
            if(mm[i] == 1){
                cout << i << " ";
            }
        }
        cout << "\n";
    }
}

F. Equalize the Array

一言不合先排序,然后统计一下每个值的出现次数,放入vector容器中,再来排序。

此时有点像在升序阶梯中求最大矩阵,可以用单调栈进行解决,不过这里直接从前往后进行模拟更新v[i] * ((int)v.size() - i)的最大值即可,遍历过程中记得统计一下cnt值,然后cnt-max(v[i] * ((int)v.size() - i))就是答案了!

 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
typedef long long ll;
#define sz std::ios::sync_with_stdio(false)
int t,n,m;
ll a[200005],f[200004];
int main()
{
    sz;
    cin >> t;
    while(t--){
        vector<int>v;
        cin >> n;
        for(int i = 1; i <= n; i++){
            cin >> a[i];
        }
        a[n + 1] = 0x3f3f3f;
        sort(a+1,a+1+n);
        int cnt = 0;
        for(int i = 1; i <= n+1; i++){
            if(i == 1){
                cnt++;
            }
            else if(a[i] == a[i-1]){
                cnt++;
            }
            else{
                v.push_back(cnt);
                cnt = 1;
            }
        }
        sort(v.begin(),v.end());
        int ans = -1;
        cnt = 0;
        for(int i = 0; i < v.size(); i++){
            cnt += v[i];
            ans = max(ans,v[i] * ((int)v.size() - i));
        }
        cout << cnt - ans << "\n";
    }
}

 

G. Old Floppy Drive

这题看了某位大佬题解才明白怎么做的orz,原来是二分模拟,看题的时候怎样都想不到二分的做法QAQ太菜了

 

@https://www.cnblogs.com/lipoicyclic/p/14411008.html    大佬的题解直接放下来了

 不妨设sum数组为前缀和数组,mx[i]代表前缀和数组里1~i最大的一个前缀和(因为可能有负数,前缀和数组不一定是单调不减,但mx数组一定是单调不减的,所以利用mx数组来进行二分查找)。

 如果mx[n] >= x,说明只遍历一遍前缀和数组一定能找到一个位置满足条件,直接在mx用lower_bound二分查找x即可。

如果mx[n] < x:意味着只遍历一轮不够。

首先,如果sum[n] <= 0,说明肯定是越更新越小(联想spfa判负环),永远也不可能停止,直接输出-1.

如果sum[n] > 0,设d = x - mx[n],则至少要循环ceil(d / sum[n])圈。但是向上取整之后在最后一圈就不一定是到mx[n]了,有可能在下标更小的位置就结束循环,这个位置可以根据lower_bound函数查找x - ceil(d * 1.0 / sum[n]) * sum[n],再加上 ceil(d * 1.0 / sum[n]) * n(每轮移动n次)即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<set>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
#define sz std::ios::sync_with_stdio(false)
ll n,t,m;
ll mm[200004];
ll a[200005];
ll f[200005];
int main()
{
    sz;
    cin >> t;
    while(t--){
        cin >> n >> m;
        f[0] = 0;
        mm[0] = 0;
        for(int i = 1; i <= n; i++) 
        {
            cin >> a[i];
            f[i] = f[i - 1] + a[i];
            mm[i] = max(mm[i - 1], f[i]);
        }
        for(int i = 1; i <= m; i++) 
        {
            ll x;
            cin >> x;
            if(mm[n] >= x){
                cout << lower_bound(mm + 1, mm + n + 1, x) - 1 - mm << ' ';
            }
            else
            {
                if(f[n] <= 0)
                {
                    cout << -1 << ' ';
                    continue;
                }
                long long d = x - mm[n];
                cout << lower_bound(mm + 1, mm + n + 1, x - f[n] * (long long)ceil(d * 1.0 / f[n])) -mm - 1 + (long long)ceil(d * 1.0 / f[n]) * n << ' ';
            }
        }
        cout << endl;
    }   
}

 

 

end~

终于补完(第一次啊),下次加油啦!希望下次div3能手速过前4题,不要那么慢了呀。

 

 

posted @ 2021-02-18 17:24  Canana  阅读(144)  评论(0)    收藏  举报