codeforces#702 所有题解

过久没打cf了,赛时只作出来3道QAQ,读题和手速如今慢的离谱,只能靠赛后补题来弥补了......html

 

A. Dense Arrayios

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

若是 y >= 2 * x , 不须要操做ide

不然不断插入 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 Remaindersui

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

为了使其都变成n/3,咱们能够从前日后推下去,增长个数向前一个数借,减小个数给下一位,模拟这一过程直到每一个数都为n/3便可code

#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 Cubesorm

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

 

#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题,不要那么慢了呀。

相关文章
相关标签/搜索