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\),而\(0\le 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} \rfloor + \lfloor \frac{\sum B}{k} \rfloor\)
现在来考虑装同一棵树的,可以发现不同的情况只和同棵树这类放置方案选取的第一种颜色(或者第二种颜色)总数对\(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\)上,如果满足:\(\begin{cases} L_j\le x\le R_j\ \\ \ L_i\le y\le 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;
}
posted @ 2020-05-02 02:14  _kiko  阅读(382)  评论(0编辑  收藏  举报