Codeforces Round #653 (Div. 3)【A - F】

题目链接:https://codeforces.com/contest/1374
这一套手速还行,但是难一点的题就不会了。最后看题解补了两题,算半AK了吧~


A - F 题解

    • A. Required Remainder
    • B. Multiply by 2, divide by 6
    • C. Move Brackets
    • D. Zero Remainder Array
    • E1. Reading Books (easy version)
    • E2. Reading Books (hard version)
    • F. Cyclic Shifts Sorting


程序开头,后面不再重复

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define ROF(i,l,r) for(int i=l;i>=r;i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rr(x,y) read(x);read(y)
#define rrr(x,y,z) read(x);read(y);read(z)
#define sss(str) scanf("%s",str+1)
#define ssf(x) scanf("%lf",&x)
#define aLL(x) x.begin(),x.end()
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=2e9;
const int sz=15;
const int mod=1e9+7;
const double eps = 1e-8;
const double pi= acos(-1);
template<class T>
inline void read(T &x)
{
    char c;x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}

A. Required Remainder

不解释

int main()
{
    int t;
    r(t);
    while(t--){
        int a,b,c;
        rrr(a,b,c);
        int k=c/a;
        m=c%a;
        if(b<=m){
            cout<<k*a+b<<endl;
        }
        else{
            cout<<(k-1)*a+b<<endl;
        }
    }
    return 0;
}

B. Multiply by 2, divide by 6

变小只能靠除以6,如果n不是只含有因数2和3的数,那肯定不行。其次其因数2的个数还不能多于因数3的个数,否则2就多于了除不尽。

int main()
{
    int t;
    r(t);
    while(t--){
        int a;
        r(a);
        n=m=0;
        while(a%2==0){
            a/=2;
            n++;
        }
        while(a%3==0){
            a/=3;
            m++;
        }
        if(a!=1||n>m){
            cout<<-1<<endl;
            continue;
        }
        cout<<(m-n)+m<<endl;
    }
    return 0;
}

C. Move Brackets

类似于括号匹配,只不过把不能匹配的都留下,最后 栈的大小/2 即为答案

int n,m;
char str[N];
int f[N];
int main()
{
    int t;
    r(t);
    while(t--){
        r(n);
        sss(str);
        stack<char> s;
        FOR(i,1,n){
            if(str[i]=='(') s.push(str[i]);
            else{
                if(s.size()&&s.top()=='('){
                    s.pop();
                }
                else{
                    s.push(str[i]);
                }
            }
        }
        cout<<s.size()/2<<endl;
    }
    return 0;
}

D. Zero Remainder Array

这题有点意思,是一个周期一样的问题
我们算出所有的 (k - ai%k) 并统计其个数
拿样例1举例 ,统计结果为 剩了2个2,1个1,1个0
Codeforces Round #653 (Div. 3)【A - F】_第1张图片
依题意知,起点就是0,两个操作每次都会+1,所以+1就是1步。最后的规律就是对统计结果取max,有相同的还要去最大值,出现次数最多的决定了要经历多少周期,最后的最大值,决定终点。

int n,m;
char str[N];
int f[N];
int main()
{
    int t;
    r(t);
    while(t--){
        rr(n,m);
        map<int,int> mm;
        int maxx=0,num=0;
        FOR(i,1,n){
            r(f[i]);
            int now=(m-f[i]%m)%m;
            if(now==0) continue;
            mm[now]++;
            if(maxx<mm[now]){
                maxx=mm[now];
                num=now;
            }
            else if(maxx==mm[now]){
                if(num<now){
                    num=now;
                }
            }
        }
        LL ans=1ll*(maxx-1)*m+num+1;
        if(maxx==0&&num==0) ans=0;
        cout<<ans<<endl;
    }
    return 0;
}

E1. Reading Books (easy version)

贪心即可,先将书分门别类并从小到大排序。一共只有2种取法,要么选择1本(1,1),要么选择1本(1,0)和1本(0,1)。哪种小选哪个就完了。

int n,m;
char str[N];
int f[N];
int main()
{
    rr(n,m);
    vector<int> v1,v2,v3;
    FOR(i,1,n){
        int a,b,c;
        rrr(a,b,c);
        if(b&&c){
            v1.pb(a);
        }
        else if(b){
            v2.pb(a);
        }
        else if(c){
            v3.pb(a);
        }
    }
    if(v1.size()+min(v2.size(),v3.size())<m){
        cout<<-1<<endl;
        return 0;
    }
    sort(aLL(v1));
    sort(aLL(v2));
    sort(aLL(v3));
    int a=0,b=0,c=0;
    LL ans=0;
    while(m--){
        int cost1=INF,cost2=INF;
        if(a<v1.size()){
            cost1=v1[a];
        }
        if(b<v2.size()&&c<v3.size()){
            cost2=v2[b]+v3[c];
        }
        if(cost1<cost2){
            a++;
            ans+=cost1;
        }
        else{
            b++;
            c++;
            ans+=cost2;
        }
    }
    cout<<ans<<endl;
    return 0;
}

E2. Reading Books (hard version)

比E1多了一个书本数的限制,范围也扩大了。
同样还是先分类排序,我们在此基础上再求前缀和
假如选了t本(1,1),那么一定选了k-t本(1,0)和(0,1)。
t + 2 ∗ ( k − t ) < = m , 故 t > = 2 k − m 。 而 t < = v [ 0 ] . s i z e ( ) , 所 以 t 的 范 围 已 经 定 了 。 t+2*(k-t)<=m ,故t>=2k-m。而t<=v[0].size(),所以t的范围已经定了。 t+2(kt)<=m,t>=2kmt<=v[0].size()t
我们遍历t,二分查找合适的最大值。详见代码~复杂度 O ( l o g ( l o g ( n ) ) ) O(log(log(n))) O(log(log(n)))

int n,m;
char str[N];
int f[N];
vector<pt> v[4];
vector<int> sm[4];
set<int> ans;
int main()
{
    int k;
    rrr(n,m,k);
    FOR(i,1,n){
        int a,b,c;
        rrr(a,b,c);
        v[3-(2*b+c)].pb(mp(a,i));
    }
    FOR(i,0,3){
        sort(aLL(v[i]));
        sm[i].pb(0);
        for(pt x:v[i]) sm[i].pb(x.fi+sm[i].back());
    }
    LL ans=2e18;
    int A,B,C,T;
    for(int t=max(0,2*k-m);t<=v[0].size()&&t<=m;t++){
        int tt=max(0,k-t);
//        cout<
        if(v[1].size()<tt||v[2].size()<tt) continue;
        int l=0,r=1e5,num;
        int a=0,b=0,c=0;
        while(l<=r){
            int mid=l+r>>1;
            int aa=max(0,lower_bound(aLL(v[1]),mp(mid,INF))-v[1].begin()-tt);
            int bb=max(0,lower_bound(aLL(v[2]),mp(mid,INF))-v[2].begin()-tt);
            int cc=lower_bound(aLL(v[3]),mp(mid,INF))-v[3].begin();
//            cout<
            if(aa+bb+cc>=m-t-2*tt){
                num=mid;a=aa;b=bb;c=cc;
                r=mid-1;
            }
            else l=mid+1;
        }
//        cout<
        if(a+b+c+t<m-2*tt) continue;
        else if(a+b+c+t==m-2*tt){
            LL res=sm[0][t]+sm[1][a+tt]+sm[2][b+tt]+sm[3][c];
            if(res<ans){
                ans=res;A=a;B=b;C=c;T=t;
            }
        }
        else{
            LL res=sm[0][t]+sm[1][a+tt]+sm[2][b+tt]+sm[3][c]-(a+b+c-(m-t-2*tt))*num;
            if(res<ans){
                ans=res;A=a;B=b;C=c;T=t;
            }
        }
//        cout<
    }
    if(ans==2e18){
        cout<<-1<<endl;
        return 0;
    }
    int len=max(0,k-T);
    cout<<ans<<endl;
    FOR(i,0,T-1) cout<<v[0][i].se<<' ';
    FOR(i,0,len-1) cout<<v[1][i].se<<' ';
    FOR(i,0,len-1) cout<<v[2][i].se<<' ';
    vector<pt> pp;
    FOR(i,1,A) pp.pb(v[1][len+i-1]);
    FOR(i,1,B) pp.pb(v[2][len+i-1]);
    FOR(i,1,C) pp.pb(v[3][i-1]);
    sort(aLL(pp));
    FOR(i,1,m-T-2*len) cout<<pp[i-1].se<<' ';
    cout<<endl;
    return 0;
}

F. Cyclic Shifts Sorting

题中所属的交换方式,只能改变偶数个逆序对,假如一个序列只有奇数个逆序对,那肯定不行?
如果这个逆序对中有相同的元素,其实他也可以。
我们可以采用类似于选择排序的思想,每次选择一个最小的,将它放在最前面。假如现在最小的在pos,目标将其放在i。如果他们相差2个位置还多,直接交换(pos-2,pos-1,pos)。否则先交换(pos-1,pos,pos+1),然后位置又相差2了,交换(pos-2,pos-1,pos),就ok了。

int n,m;
char str[N];
pt f[N];
int g[N];
void sswarp(int now)
{
    swap(g[now],g[now+2]);
    swap(g[now+1],g[now+2]);
}
int main()
{
    int t;
    r(t);
    while(t--){
        r(n);
        FOR(i,1,n){
            int a;
            r(a);
            f[i]=mp(a,i);
        }
        sort(f+1,f+n+1);
        FOR(i,1,n){
            g[f[i].se]=i;
        }
        int cnt=0;
        FOR(i,1,n){
            FOR(j,i+1,n){
                if(g[i]>g[j]) cnt++;
            }
        }
        bool flag=0;
        if(cnt&1){
            FOR(i,1,n-1){
                if(f[i].fi==f[i+1].fi){
                    swap(g[f[i].se],g[f[i+1].se]);
                    flag=1;
                    break;
                }
            }
        }
        if(!flag&&(cnt&1)){
            cout<<-1<<endl;
            continue;
        }
        vector<int> ans;
        FOR(i,1,n-2){
//            FOR(j,1,n) cout<
//            cout<
            int pos=min_element(g+i,g+n+1)-g;
//            cout<<'x'<
            while(pos!=i){
                if(pos-i>=2){
                    sswarp(pos-2);
                    ans.pb(pos-2);
                    pos-=2;
                }
                else if(pos-i==1){
                    sswarp(pos-1);
                    ans.pb(pos-1);
                    pos++;
                }
            }
        }
        cout<<ans.size()<<endl;
        for(int x:ans) cout<<x<<' ';
        cout<<endl;
    }
    return 0;
}

你可能感兴趣的:(Contests)