Codeforces Round #710 (Div. 3) (E~G)(贪心)

本题解思路和大部分代码来源于:https://www.luogu.com.cn/paste/irkatb8j

E. Restoring the Permutation(贪心)

如果q的前后两个字符不一样。那么都a,b两个串都插入后面的那个字符。

如果前后两个字符一样,那么a插入可插入的最小的那个,b插入可插入的最大的那个。

我们可以利用set的有序性来维护这一点。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<set>
#include<queue>
#include<string>
#include<map>
#include<unordered_map>
#include<sstream>
#define MAXN 10000005
#define MAXM 1000000005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n,a[200010];
int ans[200010][2];
set<int> st[2];
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)    
            scanf("%d",&a[i]);
        st[0].clear();
        st[1].clear();
        for(int i=1;i<=n;i++){
            if(a[i]!=a[i-1]){
                ans[i][0]=ans[i][1]=a[i];
                for(int j=a[i-1]+1;j<a[i];j++)
                    st[0].insert(j),st[1].insert(j);
            }
            else{
                int p=*(st[0].begin());
                ans[i][0]=p;
                st[0].erase(p);
                set<int>::iterator it=st[1].end();
                --it;
                p=*it;
                ans[i][1]=p;
                st[1].erase(p);
            }
        }
        for(int i=1;i<=n;i++)    
            printf("%d ",ans[i][0]);
        printf("\n");
        for(int i=1;i<=n;i++)    
            printf("%d ",ans[i][1]);
        printf("\n");
    }
    return 0;
}

F. Triangular Paths

如果是偶数,则会跳转到奇数。如果是奇数,则还是跳转到奇数。

故一个点只能一直向右跳。或者先向左跳一次后再向右跳。

我们需要遍历每一个要求的点。由于只能向下跳,那么就按层数从小到大排序。并按顺序遍历。

我们计算该点到下个点所在层数原本的位置。

如果要求的位置大于原本位置。由于最多除了一次向左,其他全部向右。所以要求的位置肯定只能是原本位置+1的位置。

那么就更改那个向左的。但如果单单更改那个向左的,他的下一个又会向左。故需要更改路径上每一个节点。

故修改次数为层数差。

如果要求的位置小于等于原本位置。则要修改向右走的数。

如果我们将一个向右的指针改向向左。那么会令答案向左移动两格。因此我们先尽量的选择移动两格的情况。即将向右的改向向左。

同时需要注意一下如果相差的为奇数时需要向上取整。

因此我们就令(差+1)/2为答案即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<set>
#include<queue>
#include<string>
#include<map>
#include<unordered_map>
#include<sstream>
#define MAXN 10000005
#define MAXM 1000000005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n;
pii s[200010];
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)    
            scanf("%d",&s[i].first);
        for(int i=1;i<=n;i++)    
            scanf("%d",&s[i].second);
        sort(s+1,s+n+1);
        s[0]=make_pair(1,1);
        long long ans=0;
        for(int i=1;i<=n;i++){ 
            if(s[i]==s[i-1])
                continue;
            int tar=s[i-1].second+(s[i].first-s[i-1].first);//tar为s[i]层的下标
            if((s[i-1].first+s[i-1].second)%2==0)//如果是偶数,由于一开始先向左,故--
                --tar;
            if(tar>=s[i].second)//如果要到达的点在原本到的点的左边
                ans+=(tar-s[i].second+1)/2;//将一个向右的箭头换成向左的可以令目标点向左移动1~2格。全选2的即可。 
            else//如果要到达的点在原本到的点的右边
                ans+=(s[i].first-s[i-1].first);//该点肯定在tar的右边那个点。但为了过去需要修改每一层 
        }
        printf("%lld\n",ans);
    }
    return 0;
}

G. Maximize the Remaining String(贪心)

我们从前往后遍历字符串。对于每个可加入的字符,可以先将其加入。

在之后加入时。如果暂时的答案字符串的最后一个字符小于新加入的字符且后面该最后字符还可重新加入,则将该最后字符移除。

不断移除后直到满足要求或者答案字符串为空,然后加入新字符。不断重复即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<set>
#include<queue>
#include<string>
#include<map>
#include<unordered_map>
#include<sstream>
#define MAXN 10000005
#define MAXM 1000000005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n;
int main() {
    int t;
    scanf("%d",&t);
    while(t--){
        string s, stk;
        cin>>s;
        map<char,bool>ins;
        map<char,int>last;
        for (int i = 0; i < s.size(); ++i) 
            last[s[i]]=i;//记录每个字母最后出现的次数 
        int len=s.size();
        for(int i=0;i<len;++i){
            if(ins[s[i]])//如果该字母已经被用了 
                continue;
            while(stk.size()&&stk.back()<s[i]&&last[stk.back()]>i){//如果stk还有字母,且最后的字母小于新字母,且最后的字母后面还能加 
                ins[stk.back()] = false;
                stk.pop_back();//将最后的字母移除 
            }
            stk+=s[i];//先将该字母套入。 
            ins[s[i]]=true;
        }
        cout<<stk<<endl;
    }
    return 0;
}

 

posted @ 2021-04-17 21:54  mikku  阅读(69)  评论(0)    收藏  举报