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題,不要那麼慢了呀。

相關文章
相關標籤/搜索