2018 China Collegiate Programming Contest - Guilin Site(D/H/G/J/A)

前言:单人写了一下,只写出了4题,大概铜中的水准。疯狂wawawa。

D. Bits Reverse

题目传送门


  题目类型:二进制、位运算
  解析: ABC倒置为CBA其实就是隔一位交换、那么奇数位可以互换、偶数位可以互换;分别看一下奇偶位1数量是否一样,然后贪心取。
  code:

#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define mem(a) memset(a,0,sizeof(a))
#define maxn 202020

using namespace std;
void eninit();
ll n,x,y,ttt;
ll xnt,ynt,xon[70],yon[70];

void finit(){

}

void scan(){
    cin >> x >> y ;
}

ll add(ll ned){
    xnt = ynt = 0;
    ll m = x , res = 0;
    for(ll i = 1 ; m ; ++i , m /= 2){
        if(i%2 == ned && m%2 == 1)xon[++xnt] = i;
    }
    m = y;
    for(ll i = 1 ; m ; ++i , m /= 2){
        if(i%2 == ned && m%2 == 1)yon[++ynt] = i;
    }
    if(xnt != ynt)return -1;
    for(ll i = 1 ; i <= xnt ; ++i){
        res += abs(xon[i] - yon[i])/2;
    }
    return res;
}

void solve(){
    ll res1 = 0 , res0 = 0;
    res1 = add(1);
    res0 = add(0);
    if(res1 == -1 || res0 == -1){
        cout << "Case " << ttt << ": " << -1 << endl ;
        return;
    }
    cout << "Case " << ttt << ": " << res1 + res0 << endl ;
}

int main(){
    ios::sync_with_stdio(false);
    ///cin.tie(0);cout.tie(0);
    finit();
    ll t = 1;
    cin >> t ;
    for(ttt = 1 ; ttt <= t ; ++ttt){
        scan();
        solve();
        eninit();
    }
    Lnnnb
}

void eninit(){

}

H. Hamming Distance

  题目类型:字符串、字典序、贪心
  解析:因为字典序最小、尽量从前面贪心。如果两个位置字符一样,那就直接放a;不一样的单独处理,从前向后,看看后面的不同位置够不够将汉明距离变为0,够就放a,刚好就放b或者c,不够就只能补给汉明距离大的字符串。
  code:

#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define maxn 1010101

using namespace std;
void eninit();
ll n,ttt,dif[maxn];
char a[maxn],b[maxn],s[maxn];

void finit(){

}

void scan(){
    cin >> a+1 ;
    cin >> b+1 ;
    n = strlen(a+1);
}

void solve(){
    ll dnt = 0 , lval = 0 , rval = 0;
    for(ll i = 1 ; i <= n ; ++i){
        if(a[i] == b[i])s[i] = 'a';
        else {
            dif[++dnt] = i;
        }
    }
    for(ll iii = 1 ; iii <= dnt ; ++iii){
        ll x = dif[iii];
        if(a[x] != 'a' && b[x] != 'a'){
            if(abs(lval-rval) <= dnt - iii){
                s[x] = 'a';
            }else {
                if(lval > rval){
                    s[x] = a[x];
                    rval++;
                }else {
                    s[x] = b[x];
                    lval++;
                }
            }
        }else {
            a[x] == 'a' ? rval++ : lval++ ;
            if(abs(lval-rval) <= dnt - iii){          ///只要差值<=剩下的不同的
                s[x] = 'a';
            }else {
                a[x] == 'a' ? rval-- : lval--;        ///先不取a

                if(abs(lval-rval) == dnt - iii){      ///保持不变
                    if(a[x] != 'b' && b[x] != 'b'){
                        s[x] = 'b';
                    }else {
                        if(lval > rval && a[x] == 'b')s[x] = 'b' , rval++;
                        else if(lval < rval && b[x] == 'b')s[x] = 'b' , lval++;
                        else s[x] = 'c';
                    }
                }else {                               ///差太大了
                    if(lval > rval){
                        s[x] = a[x];
                        rval++;
                    }else {
                        s[x] = b[x];
                        lval++;
                    }
                }

            }
        }
    }
    cout << "Case " << ttt << ": " << s+1 ;
}
///cout << "Case " << ttt << ": " <<  ;

int main(){
    ios::sync_with_stdio(false);
    ///cin.tie(0);cout.tie(0);
    finit();
    ll t = 1;
    cin >> t ;
    for(ttt = 1 ; ttt <= t ; ++ttt){
        scan();
        solve();
        eninit();
        if(ttt != t)cout << endl ;
    }
    Lnnnb
}

void eninit(){
    for(ll i = 0 ; i <= n+10 ; ++i){
        a[i] = b[i] = s[i] = 0;
    }
}

G. Greatest Common Divisor

  题目类型:gcd、差分
  解析:(应该能很自然的想到差分数组不变把 )为什么差分呢:想象一下,将数组排序后,假设差分数组的gcd = g。那么只要a1是g的倍数,a[i] = a[1]+k*g,就都是g的倍数。g的因子同理,所以就枚举g的因子yz,看看a1变为yz需要加多少次即可。
  code:

#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define mem(a) memset(a,0,sizeof(a))
#define maxn 202020

using namespace std;
void eninit();
ll n,ttt;
ll a[maxn];
ll gcd(ll aa,ll bb){
    return bb == 0 ? aa : gcd(bb,aa%bb);
}

void finit(){

}

void scan(){
    cin >> n ;
    for(ll i = 1 ; i <= n ; ++i){
        cin >> a[i] ;
    }
}

void solve(){
    sort(a+1,a+1+n);
    ll g = 0 , ji = 1;
    for(ll i = 1 ; i <= n ; ++i){
        g = gcd(g , a[i]);
        if(a[i]%2 == 0)ji = 0;
    }
    if(g > 1){
        cout << "Case " << ttt << ": " << 0 << endl ;
        return;
    }
    if(ji){
        cout << "Case " << ttt << ": " << 1 << endl ;
        return;
    }
    ll cha = 0;
    for(ll i = 1 ; i <= n-1 ; ++i){
        if(a[i+1] - a[i] == 0)continue;
        cha = gcd(cha , a[i+1] - a[i]);
    }
    if( cha == 1 ){
        cout << "Case " << ttt << ": " << -1 << endl ;
        return;
    }
    ll ans = 4e18;

    for(ll i = 2 ; i*i <= cha ; ++i){
        if(cha %i == 0){
            ll x = i , y = cha/i;
            ans = min(ans , (x - a[1]%x)%x );
            ans = min(ans , (y - a[1]%y)%y );
        }
    }
    ans = min(ans , (cha - a[1]%cha)%cha );
    cout << "Case " << ttt << ": " << ans << endl ;
}

int main(){
    ios::sync_with_stdio(false);
    ///cin.tie(0);cout.tie(0);
    finit();
    ll t = 1;
    cin >> t ;
    for(ttt = 1 ; ttt <= t ; ++ttt){
        scan();
        solve();
        eninit();
    }
    Lnnnb
}

void eninit(){

}

J. Stone Game

  题目类型:博弈、拓扑排序
  解析:此题胜负完全不由决策决定。因为相邻的数不相同,所以总会有a[i]满足a[i-1] > a[i] && a[i+1] > a[i],那么a[i]就可以变为0。
  这个数组相当于相邻的数有一条边,小的指向大的数,一个有向无环图,所以比两边都小的加入队列,逐步减少其他点的入度,拓扑排序一下即可。
  比如:2 3 4 1
  第一个数和第四个数可以变成0:0 3 4 0
  第二个数变成1:0 1 4 0
  第三个数变成2:0 1 2 0
  计算新数组和原来数组的差值和,奇数A赢,偶数B赢。
  code:

#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define maxn 1010101

using namespace std;
void eninit();
ll n,ttt;
ll a[maxn],c[maxn],vis[maxn];
queue<ll>q;

void finit(){

}

void scan(){
    cin >> n ;
    for(ll i = 1 ; i <= n ; ++i){
        cin >> a[i] ;
    }
}

ll check(ll i){
    ll lf = (a[i-1] > a[i] || vis[i-1]);
    ll rg = (a[i+1] > a[i] || vis[i+1]);
    return (lf && rg);
}

void solve(){
    ll sum = 0;
    a[0] = a[n+1] = 1e9;
    vis[0] = vis[n+1] = 1;
    for(ll i = 1 ; i <= n ; ++i){
        if(a[i-1] > a[i] && a[i] < a[i+1] && !vis[i]){
            q.push(i);
        }
    }
    while(!q.empty()){
        ll top = q.front();
        q.pop();
        vis[top] = 1;
        ll l = top-1 , r = top+1;
        if(!vis[l] && check(l)){
            vis[l] = 1;
            q.push(l);
            c[l] = max(c[l-1] , c[l+1]) + 1;
        }
        if(!vis[r] && check(r)){
            vis[r] = 1;
            q.push(r);
            c[r] = max(c[r-1] , c[r+1]) + 1;
        }
    }
    for(ll i = 1 ; i <= n ; ++i){
        sum += (a[i] - c[i]);
    }
    if(sum%2 == 1)cout << "Case " << ttt << ": " << "Alice" ;
    else cout << "Case " << ttt << ": " << "Bob" ;
}
///cout << "Case " << ttt << ": " << ;

int main(){
    ios::sync_with_stdio(false);
    ///cin.tie(0);cout.tie(0);
    finit();
    ll t = 1;
    cin >> t ;
    for(ttt = 1 ; ttt <= t ; ++ttt){
        scan();
        solve();
        eninit();
        if(ttt != t)cout << endl ;
    }
    Lnnnb
}

void eninit(){
    for(ll i = 0 ; i <= n+10 ; ++i){
        c[i] = vis[i] = 0;
    }
}

A. Array Merge

  题目类型:单调栈、相邻比较法、连续序列平均值
  解析:想一下,最后的序列肯定是AA…B…A…B…
  并且要分别维护A、B数组在原序列的顺序,考虑相邻比较法,可以交换相邻的一段A和一段B。
  交换后的变化以及具体式子见大佬博客
  然后用单调栈维护(连续序列平均值)的递减
  code:

#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define maxn 202020

using namespace std;
void eninit();
ll nnn,mmm,ttt;
ll snt,sat,sbt,aaa[maxn],bbb[maxn];
struct seg{
    ll sum,l,r,len;
}st[maxn],saa[maxn],sbb[maxn];
///单调栈合并递减平均子序列
void merge_(ll *a,ll len,seg *s,ll &lennnn){
    snt = 0;
    for(ll i = 1 ; i <= len ; ++i){
        if(!snt || st[snt].sum > a[i]*(st[snt].len)){
            st[++snt] = {a[i] , i , i , 1};
        }else {
            st[snt].sum += a[i];
            st[snt].r = i;
            st[snt].len++;
            while(snt >= 2 && st[snt].sum*st[snt-1].len >= st[snt-1].sum*st[snt].len ){
                st[snt-1] = {st[snt].sum+st[snt-1].sum , st[snt-1].l , st[snt].r , st[snt].len+st[snt-1].len};
                --snt;
            }
        }
    }
    for(ll i = 1 ; i <= snt ; ++i)s[i] = st[i];
    lennnn = snt;
}

ll coun(ll *a,ll hav,ll l,ll r){
    ll res = 0;
    for(ll i = l , num = 1 ; i <= r ; ++i , ++num){
        res += a[i] * (hav + num);
    }
    return res;
}

void finit(){

}

void scan(){
    cin >> nnn >> mmm ;
    for(ll i = 1 ; i <= nnn ; ++i)cin >> aaa[i] ;
    for(ll i = 1 ; i <= mmm ; ++i)cin >> bbb[i] ;
}

void solve(){
    merge_(aaa,nnn,saa,sat);
    merge_(bbb,mmm,sbb,sbt);
    ll l = 1 , r = 1 , hav = 0 , ans = 0;
    while(l <= sat && r <= sbt){
        if(saa[l].sum*sbb[r].len >= sbb[r].sum*saa[l].len){
            ans += coun(aaa,hav,saa[l].l , saa[l].r);
            hav += saa[l++].len;
        }else {
            ans += coun(bbb,hav,sbb[r].l , sbb[r].r);
            hav += sbb[r++].len;
        }
    }
    while(l <= sat){
        ans += coun(aaa,hav,saa[l].l , saa[l].r);
        hav += saa[l++].len;
    }
    while(r <= sbt){
        ans += coun(bbb,hav,sbb[r].l , sbb[r].r);
        hav += sbb[r++].len;
    }
    cout << "Case " << ttt << ": " << ans ;
}
///cout << "Case " << ttt << ": " << ;

int main(){
    ios::sync_with_stdio(false);
    ///cin.tie(0);cout.tie(0);
    finit();
    ll t = 1;
    cin >> t ;
    for(ttt = 1 ; ttt <= t ; ++ttt){
        scan();
        solve();
        eninit();
        if(ttt != t)cout << endl ;
    }
    Lnnnb
}

void eninit(){

}

总结

1.字典序还是要直接从前面考虑,不知道写H的时候怎么想的,整了个前后指针,debug了半天。
2.输出格式,还有不常见的数组大小开大点。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值