Educational Codeforces Round 96 (Rated for Div. 2)(A-E题解)

Educational Codeforces Round 96 (Rated for Div. 2)(A-E题解)_第1张图片
Educational Codeforces Round 96 (Rated for Div. 2)(A-E题解)_第2张图片
题目大意:
给你一个 n n n,求解 3 x + 5 y + 7 z = n 3x+5y+7z=n 3x+5y+7z=n的解。
思路:
暴力枚举即可。
代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 2e5 + 10;
void solved(){
    int n;cin>>n;
    for(int i = 0; i <= n / 3; i++){
        for(int j = 0; j <= n / 5; j++){
            for(int k = 0; k <= n / 7; k++){
                if(i * 3 + j * 5 + k * 7 == n){
                    cout<<i<<" "<<j<<" "<<k<<endl;
                    return ;
                }
            }
        }
    }
    cout<<"-1"<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)
        solved();
    return 0;
}

Educational Codeforces Round 96 (Rated for Div. 2)(A-E题解)_第3张图片
题目大意:
你有 n n n个水桶,每个水桶可以装无限的水,一开始每个水桶有 a i ai ai的水,现在你可以操作 k k k次,每次选择两个水桶将一个水桶的水倒到另外一个水桶里面(水量任意),问 k k k次操作之后水桶水最多的与最少的差的最大值是多少?
思路:
每次把第二大的水全部倒在最大水的桶里面,模拟 k k k次即可。
代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 2e5 + 10;
typedef long long int ll;
ll a[maxn];
void solved(){
    int n,k;cin>>n>>k;
    for(int i = 1; i <= n; i++)cin>>a[i];
    sort(a + 1 ,a + 1 + n);
    ll ans = abs(a[1] - a[n]);
    int id = n - 1;
    for(int i = 1; i <= k; i++){
        a[n] += a[id];
        id--;
        if(id < 0)break;
    }
    cout<<max(a[n],ans)<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)
        solved();
    return 0;
}

Educational Codeforces Round 96 (Rated for Div. 2)(A-E题解)_第4张图片
题目大意:
你有 n n n个数( 1 − n 1-n 1n),现在你要操作 n − 1 n-1 n1次,每次从队列移除两个数 a , b a,b a,b,然后把 ( a + b + 1 ) / 2 (a+b+1)/2 (a+b+1)/2加入队列,问你操作 n − 1 n-1 n1次后的最小值是多少?并且把每次操作的 a , b a,b a,b打印出来。
思路:
每次操作选择最大的两个数,考虑到向上取整,我们尽可能每次操作的两个数要么是奇数+奇数=偶数,偶数+偶数=偶数,实在不行就奇数+偶数=奇数,用两个优先队列维护即可,一个维护奇数一个维护偶数。
代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 2e5 + 10;
void solved(){
    int n;cin>>n;
    priority_queue<int,vector<int>,less<int>>odd;
    priority_queue<int,vector<int>,less<int>>even;
    for(int i = 1; i <= n; i++){
        if(i & 1)odd.push(i);
        else even.push(i);
    }
    vector<pair<int,int> >ve;
    for(int i = 1; i <= n - 1; i++){
        int x = 0,a = 0,b = 0;
        if(odd.size() >= 2 && even.empty() || odd.top() > even.top()){
            a = odd.top();odd.pop();
            b = odd.top();odd.pop();
            x = (a + b + 1) / 2;
        }else if(even.size() >= 2){
            a = even.top();even.pop();
            b = even.top();even.pop();
            x = (a + b + 1) / 2;
        }else{
            a = odd.top();odd.pop();
            b = even.top();even.pop();
            x = (a + b + 1) / 2;
        }
        ve.push_back({a,b});
        if(x & 1)odd.push(x);
        else even.push(x);
    }
    if(!even.empty())cout<<even.top()<<endl;
    if(!odd.empty())cout<<odd.top()<<endl;
    for(int i = 0; i < ve.size(); i++)cout<<ve[i].first<<" "<<ve[i].second<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)
        solved();
    return 0;
}

Educational Codeforces Round 96 (Rated for Div. 2)(A-E题解)_第5张图片
Educational Codeforces Round 96 (Rated for Div. 2)(A-E题解)_第6张图片
题目大意:
给你一个长度为 n n n 01 01 01串,每次选择一个 i n d e x = [ 1 , n ] index=[1,n] index=[1,n]执行两个操作,先删除 s i si si,然后从这个串中再删除最大的前缀字符,问这个串最多能操作多少次?
思路:
贪心:为了使得操作次数越多,我们可能希望每次删除后剩下的字符串都尽可能的长。
我们先把连续的 01 01 01长度转化为整数数组,然后开始考虑。
因为每次无论你的 i n d e x index index选的哪里,前缀都会被删除,那么为了操作次数越多,我可以选择前缀长度 > 1 >1 >1的,然后删除掉,为什么长度要 > 1 >1 >1,因为你选择后面的话,这个前缀不但没了,而且你后面的也会少一个,那我为什么不知道选择前缀中的一个删除呢?
选一个删一个前缀即前缀 > 1 >1 >1.当前缀 = 1 =1 =1的时候,如果直接删除可能删除之后就是一个很长的连续的串这样我们会损失很多长度,所以当遇到当前长度 = 1 =1 =1的时候,我们到后面去找一个>1的串然后删掉一个,这样就能保证我们这次操作最多损失两个字符,这是最优的,如果找不到就计算剩下串的长度除2向上取整即可。
从当前位置到后面去找暴力的话是 O ( n 2 ) O(n^2) O(n2)这样会超时,用双指针就能解决了。
代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 2e5 + 10;
void solved(){
    int n;cin>>n;
    string s;cin>>s;
    vector<int>ve;
    for(int i = 0,j; i < n; i = j){
        for(j = i; j < n && s[i] == s[j]; j++);
            ve.push_back(j - i);
    }
    int m = ve.size();
    int l = 0,r = 1;
    int ans = 0;
    for(;l < m; l++){
        if(ve[l] > 1)ans++;
        else{
            while(r <= l)r++;
            while(r < m && ve[r] <= 1)r++;
            if(r == m){
                cout<<ans + (m - l + 1) / 2<<endl;
                return;
            }else{
                ve[r]--;ans++;
            }
        }
    }
    cout<<ans<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)
        solved();
    return 0;
}

Educational Codeforces Round 96 (Rated for Div. 2)(A-E题解)_第7张图片
题目大意:
给你一个字符串,每次可以交换两个相邻的元素,问从原串到原串的翻转的最小交换次数。
思路:
相邻最小交换次数容易想到求逆序对,考虑如何把这个问题转化到与这方面有关上。
我们可以先对原串到 1 − n 1-n 1n编号,然后转置后可以求得编号,由于有相同的元素存在,所以我们从原串到转置串的编号他们直接的距离 ∣ i − j ∣ |i-j| ij应该尽可能的小,也就是原串如果有多个相同的字符,转置求编号时应该选择最近的,然后编号求逆序对即可。
逆序对可以归并排序或者线段树树状数组都可以 O ( n l o g n ) O(nlogn) O(nlogn)高效求得。
代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

#define mid (l + r) / 2
#define lson (rt * 2)
#define rson (rt * 2 + 1)
const int maxn = 4e5 + 10;
char s[maxn],t[maxn];
int cnt[30];
int m[maxn << 2];
typedef long long int ll;
int query(int rt,int l,int r,int ql,int qr){
    if(l >= ql && r <= qr)return m[rt];
    int ans = 0;
    if(ql <= mid) ans += query(lson,l,mid,ql,qr);
    if(qr > mid) ans += query(rson,mid + 1,r,ql,qr);
    return ans;
}
void update(int rt,int l,int r,int pos){
    if(l == r){ m[rt]++;return ;}
    if(pos <= mid)update(lson,l,mid,pos);
    else update(rson,mid + 1,r,pos);
    m[rt] = m[lson] + m[rson];
}
void solved(){
    int n;scanf("%d%s",&n,s + 1);
    for(int i = n,j = 1; i >= 1; i--,j++)t[i] = s[j];
    vector<int>ve[30];
    for(int i = 1; i <= n; i++){
        ve[s[i] - 'a' + 1].push_back(i);
    }
    ll ans = 0;
    for(int i = 1; i <= n; i++){
        int x = ve[t[i] - 'a' + 1][cnt[t[i] - 'a' + 1]++];
        ans += query(1,1,maxn,x + 1,maxn);
        update(1,1,maxn,x);
    }
    cout<<ans<<endl;
}
int main(){
    solved();
    return 0;
}

你可能感兴趣的:(思维题,算法,数据结构,思维)