Codeforces Round #638 (Div. 2)

Posted kikokiko

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #638 (Div. 2)相关的知识,希望对你有一定的参考价值。

Codeforces Round #638 (Div. 2)

A - Phoenix and Balance
最大的那个比其他所有的和都要大
所以最大那个的配上最小的(frac{n}{2}-1)个分成一组

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
int n;
void solve(){
    cin >> n;
    int ret1 = 0, ret2 = 0;
    for(int i = 1; i <= n; i++) ret1 += (1<<i);
    for(int i = 1; i <= n / 2 - 1; i++) ret2 += (1<<i);
    ret2 += (1<<n);
    cout << abs(ret1 - ret2 - ret2) << endl;
}
int main(){
    ____();
    int T; for(cin >> T; T; T--) solve();   
    return 0;
}

B - Phoenix and Beauty
其实就要构造一个循环节为(k)的循环串
那么如果不同的数出现次数大于(k),就不可能构造出来
否则先取不同的数字,然后补全长度到(k)
复制(100)遍就好了
复制一百遍能保证原序列必然能作为当前序列的一个子序列出现

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 222;
int n,k,A[MAXN];
void solve(){
    cin >> n >> k;
    vector<int> vec;
    for(int i = 1; i <= n; i++){
        cin >> A[i];
        vec.emplace_back(A[i]);
    }
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    if(vec.size()>k){
        cout << -1 << endl;
        return;
    }
    while(vec.size()<k) vec.emplace_back(1);
    cout << vec.size() * 100 << endl;
    for(int i = 1; i <= 100; i++) for(int x : vec) cout << x << ‘ ‘;
    cout << endl;
}
int main(){
    ____();
    int T; for(cin >> T; T; T--) solve();
    return 0;
}

C - Phoenix and Distribution

因为和原串顺序没关系,可以先把原串排个序,好操作
因为每个串都不能是空的,所以首先贪心地把前(k)个字符赋给(k)个字符串

1.这个时候如果这(k)个字符不完全一样,那么可以直接输出最大的那个,因为其他字符可以接在最小的那个后面,字典序必然是第一个字符最大的那个大

2.现在考虑前(k)个字符相同的情况

  • 那么如果剩下的(n-k)个字符完全相同,那么就可以把剩下的(n-k)个字符分配到(k)个字符串上,然后取最长的那个就是字典序最大的

  • 如果不完全相同,就可以直接把剩下的全部接在第一个字符之后然后输出
    可以这样考虑,如果现在还是把这(n-k)个字符依次循环分配到(k)个字符串上,那么对于某一个串必然存在这么一个位置,这个位置的字符和
    它上一个串的这个位置是不同的,那么按最开始的办法,把剩下的字符全部接在字典序小的后面,但其实这样不是最优的
    如果分配完前(k)个字符之后,把剩下的(k-n)个全部接在第一个串后面必然更优,因为这样大的那个字符出现的位置会往后推

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;

int n,k,cnt[26],m;
char s[MAXN],t[MAXN];

void solve(){
    cin >> n >> k >> (s+1);
    sort(s+1,s+1+n);
    if(k==1){
        cout << s+1 << endl;
        return;
    }
    bool same = true;
    for(int i = 2; i <= k; i++){
        if(s[i]!=s[i-1]){
            same = false;
            break;
        }
    }
    if(!same){
        cout << s[k] << endl;
        return;
    }
    set<char> S;
    for(int i = k + 1; i <= n; i++) S.insert(s[i]);
    if(S.empty()){
        cout << s[1] << endl;
        return;
    }
    if(S.size()>1){
        cout << (s+k) << endl;
        return;
    }
    cout << s[1]; for(int i = 1; i <= (n-k)/k + ((n-k)%k!=0?1:0); i++) cout << s[k+1];
    cout << endl;

}
int main(){
    ____();
    int T; for(cin >> T; T; T--) solve();
    return 0;
}

D - Phoenix and Science
假设我们记当前的总质量为(w),细菌数量为(x),那么对于当前这天,我可以选择让(y)个细菌分裂,那么下一天细菌的数量就会变成(x+y),同时总质量会变成(w+x+y),而(0le y le x),所以细菌数量最多增加一倍
考虑如何能够最快到达(n),因为细菌数量(x)是不会减少的,所以我们必须保证当前这天的总质量(w)和需要到达的总质量(n)的差值(delta)小于等于(x),这样就可以限定我们这一天最多能分裂多少细菌,使得下一天的(delta)小于下一天的细菌数量(x),这给我们提供了一个上限,所以为了能尽快到达(n),最优的办法就是分裂选取这个最大值,同时不能超过当前的细菌数量,贪心分裂就好了

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
int n;
void solve(){
    cin >> n;
    int tot = 1, add = 1;
    vector<int> vec;
    while(tot<=n){
        int delta = n - tot;
        if(add*2>=delta){
            vec.push_back(delta-add);
            break;
        }
        vec.push_back(min(delta/2-add,add));
        add += vec.back();
        tot += add;
    }
    cout << vec.size() << endl;
    for(int x : vec) cout << x << ‘ ‘; cout << endl;
}

int main(){
    ____();
    int T; for(cin >> T; T; T--) solve();
    return 0;
}

E - Phoenix and Berries
最简单的情况就是每个框子只装同种颜色的,这时候最多装(lfloor frac{sum A}{k} floor + lfloor frac{sum B}{k} floor)
现在来考虑装同一棵树的,可以发现不同的情况只和同棵树这类放置方案选取的第一种颜色(或者第二种颜色)总数对(k)的模数有关
所以可以背包搞出来
这时候取模掉的那些可以直接按同颜色的装

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 555;
using LL = int_fast64_t;
LL n,k,A[MAXN],B[MAXN];
bool f[2][MAXN];

int main(){
    ____();
    cin >> n >> k;
    LL tota = 0, totb = 0;
    for(int i = 1; i <= n; i++) cin >> A[i] >> B[i], tota += A[i], totb += B[i];
    LL ret = tota/k + totb/k;
    int tg = 0; f[tg][0] = true;
    for(int i = 1; i <= n; i++){
        tg ^= 1;
        memcpy(f[tg],f[tg^1],sizeof(f[tg]));
        for(int pre = 0; pre < k; pre++){
            if(!f[tg^1][pre]) continue;
            for(int cur = 1; cur <= min(A[i],k); cur++){
                if(k-cur>B[i]) continue;
                f[tg][(pre+cur)%k] = true;
            }
        }
    }
    for(int i = 1; i < k; i++) if(f[tg][i]) ret = max(ret,(tota-i)/k+(totb-(k-i))/k+1);
    cout << ret << endl;
    return 0;
}

F - Phoenix and Memory
因为保证合法,所以找到一个解十分简单,建一个优先队列,枚举(i)(1)(n),如果有以当前点为左端点的区间,就把这些区间放到优先队列里去,每次选择右端点最靠左的那个放到当前位置,这样贪心做肯定可以得到一组解

现在考虑怎么判断解唯一
如果解不唯一,那么必然存在两个位置的点可以互换,现在就要找出一对这样可以交换的点就好了
对于之前的一段可选区间([L_i,R_i])如果把他放在位置(x)上,现在的一段可选区间([L_j,R_j]),放在位置(y)上,如果满足:(egin{cases} L_jle xle R_j \ L_ile yle R_i end{cases})
那就说明这两个位置是可以交换的,这个可以用线段树做,每次确定一个区间的位置了之后,就把这个区间的右端点,赋给这个点,然后我们对于当前放置在(i)点的区间([L_i,R_i]),我们找([L_i,i))之间的最大值,如果大于等于(i),就必然存在可以交换的点了,暴力找出这个点就好了
找到之后对于后面的位置,唯一去确定就好了,因为已经找到两个不同序列了

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
const int INF = 0x3f3f3f3f;
int n,dz[MAXN];
vector<pair<int,pair<int,int>>> vec[MAXN];
int rmax[MAXN];
template<typename T>
struct SegmentTree{
    T maxx[MAXN<<2],lazy[MAXN<<2];
    int l[MAXN<<2],r[MAXN<<2];
    #define ls(rt) rt << 1
    #define rs(rt) rt << 1 | 1
    #define pushup(rt) maxx[rt] = max(maxx[ls(rt)],maxx[rs(rt)])
    void build(int L, int R, int rt){
        l[rt] = L; r[rt] = R;
        lazy[rt] = 0;
        if(L+1==R) return;
        int mid = (L + R) >> 1;
        build(L,mid,ls(rt)); build(mid,R,rs(rt));
    }
    void pushdown(int rt){
        if(!lazy[rt]) return;
        lazy[ls(rt)] += lazy[rt]; lazy[rs(rt)] += lazy[rt];
        maxx[ls(rt)] += lazy[rt]; maxx[rs(rt)] += lazy[rt];
        lazy[rt] = 0;
    }
    void update(int L, int R, int rt, T x){
        if(L>=r[rt] || l[rt]>=R) return;
        if(L<=l[rt] && r[rt]<=R){
            lazy[rt] += x; maxx[rt] += x;
            return;
        }
        pushdown(rt);
        update(L,R,ls(rt),x); update(L,R,rs(rt),x);
        pushup(rt);
    }
    T query(int L, int R, int rt){
        if(L>=r[rt] || l[rt]>=R) return -INF;
        if(L<=l[rt] && r[rt]<=R) return maxx[rt];
        pushdown(rt);
        return max(query(L,R,ls(rt)),query(L,R,rs(rt)));
    }
};
SegmentTree<int> ST;
int main(){
    ____();
    cin >> n;
    for(int i = 0; i < n; i++){
        int l, r; cin >> l >> r;
        l--, r--;
        rmax[i] = r;
        vec[l].push_back(make_pair(r,make_pair(l,i)));
    }
    priority_queue<pair<int,pair<int,int>>,vector<pair<int,pair<int,int>>>,greater<pair<int,pair<int,int>>>> que;
    ST.build(0,n,1);
    bool unq = true;
    vector<int> ret1,ret2;
    for(int i = 0; i < n; i++){
        for(auto seg : vec[i]) que.push(seg);
        auto p = que.top();
        que.pop();
        ret1.push_back(p.second.second);
        if(!unq){
            ret2.push_back(p.second.second);
            continue;
        }
        ST.update(i,i+1,1,p.first);
        if(!i) continue;
        int maxx = ST.query(p.second.first,i,1);
        if(maxx<i) continue;
        unq = false;
        int pos = 0;
        for(int j = p.second.first; j < i; j++){
            if(rmax[ret1[j]]>=i){
                pos = j;
                break;
            }
        }
        copy(ret1.begin(),ret1.end(),back_inserter(ret2));
        swap(ret2[pos],ret2[i]);
    }
    if(unq){
        cout << "YES" << endl;
        for(int i = 0; i < n; i++) dz[ret1[i]] = i+1;
        for(int i = 0; i < n; i++) cout << dz[i] << ‘ ‘; cout << endl;
    }
    else{
        cout << "NO" << endl;
        for(int i = 0; i < n; i++) dz[ret1[i]] = i+1;
        for(int i = 0; i < n; i++) cout << dz[i] << ‘ ‘; cout << endl;
        for(int i = 0; i < n; i++) dz[ret2[i]] = i+1;
        for(int i = 0; i < n; i++) cout << dz[i] << ‘ ‘; cout << endl;
    }
    return 0;
}

以上是关于Codeforces Round #638 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #638 (Div. 2)

Codeforces Round #638 (Div. 2)

Codeforces Round #638 (Div. 2)

Codeforces Round #638 (Div. 2)(A~B)

Codeforces Round #638 (Div. 2) A~C题解

CF A. Phoenix and Balance Codeforces Round #638 (Div. 2) 5月1号