2015ACM/ICPC亚洲区上海站

这是准备第一次打正式的区域赛前模拟做的一套题,作为比赛前的最后一次模拟训练。希望自己在比赛上不拖队友后腿(队友tql),能够发挥一个作为数学和数据结构选手的作用。

也希望自己在接下来的ACM生涯中能够

以梦为马,不负韶华。

F题 Friendship of Frog

本题便是全场的签到题,不多赘述。线性处理,记录上一个位置即可。

//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
#include<stack>0
#include<time.h>
using namespace std;
const int p = 1e9+7;
const int N = 2e3+5;
const int maxn = 1e5+5;
const long long INF = 1e9;
#define REP(i,n) for(ll i = 1; i <= n; ++i)
#define REPA(i,j,n) for(ll i = j; i <= n; ++i)
#define RREP(i,n) for(ll i = n; i >= 1; --i)
#define REPR(i,j,n) for(ll i = n; i >= j; --i)
#define lll __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,ll> pdi;
int t;
ll n, m;
ll a, b, mod;
inline int read(){
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
int pos[26];int Case = 0;
char s[N];
void solve(){
    cin>>s+1;
    int ans = INF;
    for(int i = 0; i <=25; ++i)pos[i] = 0;
    for(int i = 1; i <= strlen(s+1); ++i){
        if(!pos[s[i]-'a'])pos[s[i]-'a'] = i;
        else {
            ans = min(ans,i - pos[s[i]-'a']);
            pos[s[i]-'a'] = i;
        }
    }
    if(ans == INF)ans = -1;
    cout<<"Case #"<<Case<<": "<<ans<<'\n';
}

int main(){
    //ios::sync_with_stdio(0);
    //cin.tie(0);
    //cout.tie(0);
#ifdef ACM
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    t = 1;
    //srand((unsigned)time(NULL));
    scanf("%lld",&t);

    while (t--){
        ++Case;
        solve();
    }

    fclose(stdin);
    fclose(stdout);
}

K题 Kingdom of Black and White

思维题。还是蛮好做的,就是被long long 卡了半天,明明N有1e5,我还开了int,我太菜了。
本题主要就是分析一下两种情况,要么是两个连续的不同颜色的串,我们去更改一个端点,要么就是改变一个点,然后将左右两侧相连。
预处理每个变色的端点左右两侧的连续串长度即可,复杂度O(n)。
当然其实也可以直接单独把每一串长度单独保存,可以更加方便的处理,常数更优。

//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
#include<stack>
#include<time.h>
using namespace std;
const int p = 1e9+7;
const int N = 2e3+5;
const int maxn = 1e5+5;
const long long INF = 1e9;
#define REP(i,n) for(ll i = 1; i <= n; ++i)
#define REPA(i,j,n) for(ll i = j; i <= n; ++i)
#define RREP(i,n) for(ll i = n; i >= 1; --i)
#define REPR(i,j,n) for(ll i = n; i >= j; --i)
#define lll __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,ll> pdi;
int t;
ll n, m;
inline int read(){
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
ll l[N], r[N];
char s[N];
int Case;
void solve(){
    cin>>s+1;
    ll len = strlen(s+1);
    ll ans = 0;
    ll nowlen = 1;
    for(int i = 0; i <= len ;++i)l[i] = r[i] = 0;//其实可以去掉(
    for(int i = 2; i <= len; ++i){//预处理左边
        if(s[i] != s[i-1]){
            l[i-1] = nowlen;
            nowlen = 1;
        } else ++nowlen;
    }
    nowlen = 1;
    for(int i = len-1 ; i >= 1; --i){//预处理右侧
        if(s[i] != s[i+1]){
            r[i+1] = nowlen;
            nowlen = 1;
        } else ++nowlen;
    }
    nowlen = 1;
    for(int i = 2; i <= len ; ++i){//先获取本来的总和
        if(s[i] != s[i-1]){
            ans += nowlen * nowlen;
            nowlen = 1;
        } else ++nowlen;
    }
    ans += nowlen * nowlen;
    ll res = 0;
    for(int i = 2; i <= len ;++i){//寻找最优修改点
        if(i < len && s[i] != s[i-1] && s[i] != s[i+1]){
            res = max(res,(ll)(2*r[i+1]*l[i-1]+2*(l[i-1]+r[i+1])));
        } else if(s[i] != s[i-1]){
            int llen = l[i-1], rlen = r[i];
            res = max(res,2*1ll*(abs(llen-rlen+1)));
        }
    }
    ans += res;
    cout<<"Case #"<<Case<<": "<<ans<<'\n';
}

int main(){
    //ios::sync_with_stdio(0);
    //cin.tie(0);
    //cout.tie(0);
#ifdef ACM
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    t = 1;

    //srand((unsigned)time(NULL));
    scanf("%lld",&t);
    while (t--){
        ++Case;
        solve();
    }

    fclose(stdin);
    fclose(stdout);
}

L题 LCM Walk

这是一道比较简单的数论题。我们只需要仔细的倒着推即可,且大致可以估算复杂度比较低(以下解法我无法给出一个比较准确的复杂度,因为我实在是太菜了,大佬们可以自己证明,或着查询其他文章)。
对于这题,我们直接考虑最后一步,注意到每一步都走一个LCM,即:增加的那个坐标一定是接下来那个坐标对中的较大者。我们去分析上一步,然后我们将每一个数都看成最大公约数乘上一个数的形式即可。

//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
#include<stack>
#include<time.h>
using namespace std;
const int p = 1e9+7;
const int N = 2e3+5;
const int maxn = 1e5+5;
const long long INF = 1e9;
#define REP(i,n) for(ll i = 1; i <= n; ++i)
#define REPA(i,j,n) for(ll i = j; i <= n; ++i)
#define RREP(i,n) for(ll i = n; i >= 1; --i)
#define REPR(i,j,n) for(ll i = n; i >= j; --i)
#define lll __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,ll> pdi;
int t;
ll n, m;
inline int read(){
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
ll gcd(ll a,ll b){
    ll res;
    while(b){
        res = a % b;
        a = b;
        b = res;
    }
    return a;
}
ll lcm(ll a,ll b){return a * b / gcd(a,b);}
ll ex, ey;
ll ix, iy;
int Case;
void solve(){
    cin>>ex>>ey;
    ll ans = 1;
    while(1){
        if(ex > ey)swap(ex,ey);
        ll g = gcd(ex,ey);
        ll ix = ex + g;
        if(ey % ix == 0){
            ey = ey * g / ix;
            ++ans;
        }
        else break;
    }
    cout<<"Case #"<<Case<<": "<<ans<<'\n';
}

int main(){
    //ios::sync_with_stdio(0);
    //cin.tie(0);
    //cout.tie(0);
#ifdef ACM
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    t = 1;

    //srand((unsigned)time(NULL));
    scanf("%lld",&t);
    while (t--){
        ++Case;
        solve();
    }

    fclose(stdin);
    fclose(stdout);
}

A题是道几何体,姑且先咕咕咕了。。。

B题 Binary Tree

这是一道不错的思维题,考察了对二进制的理解。这题卡了我大半天,我实在太菜了。
解题思路:
首先我们需要充分利用题目给我们的信息,提示。比如数据范围?这题的突破口就在于数据范围,我们注意到有2^k>=n,且我们必须走k层,如果我们走k层,把每一层的和加起来,那么最小值就是一直往左边走的情况,即pow(2,k)-1,而如果在最后一层选择向右走,则有pow(2,k),直觉上似乎我们只需要一直向左走就可以了,不然的话,这题不仅很难考虑,而且数据范围也不是特别有必要。我们思考,如果我们先向左走,每个值都加起来,然后我们思考,如果我们减去一个数,会导致当前的和变为nowsum - nowsub*2,由于我们一直往左走,所以路径上每一个值都是二的整数幂,如果我们考虑可以减去任意二次幂的和,那么我们就可以构造出任何一个被减数,由于乘2buff导致我们所有的若干二次幂的和乘2,这样就导致了1无法单独减去,而其他任意小于当前总和的数都可以减去,在考虑道最后一层的1,我们就可以随意支配了。

//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
#include<stack>
#include<time.h>
using namespace std;
const int p = 1e9+7;
const int N = 2e3+5;
const int maxn = 1e5+5;
const long long INF = 1e9;
#define REP(i,n) for(ll i = 1; i <= n; ++i)
#define REPA(i,j,n) for(ll i = j; i <= n; ++i)
#define RREP(i,n) for(ll i = n; i >= 1; --i)
#define REPR(i,j,n) for(ll i = n; i >= j; --i)
#define lll __int128
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,ll> pdi;
int t;
ll n, m;
ll k;
inline int read(){
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
int Case;
ll fast(ll a, ll b){
    ll res = 1;
    while(b){
        if(b & 1) res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}
void solve(){
    cin>>n>>k;
    printf("Case #%d:\n",Case);
    int f = 0;
    if(n & 1) f = 1;//奇偶判断
    else n --;//如果为偶数,就先转化为奇数的情况,方便最后一层的处理
    ll sum = fast(2,k) - 1;//奇数情况的和
    ll d = sum - (sum - n) / 2;
    ll res = 1;
    while(d > 1){
        if(d & 1)cout<<res<<" +\n";
        else cout<<res<<" -\n";
        d >>= 1;
        res *= 2;
    }
    if(f)cout<<res<<" +\n";
    else cout<<res+1<<" +\n";
}
int main(){
    //ios::sync_with_stdio(0);
    //cin.tie(0);
    //cout.tie(0);ertg
#ifdef ACM
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    t = 1;

    //srand((unsigned)time(NULL));
    scanf("%lld",&t);

    while (t--){
        ++Case;
        solve();
    }

    fclose(stdin);
    fclose(stdout);
}


由于最后一天比较累(只睡了两三个小时,题解写的仓促,逻辑有很多问题),但暂时不改了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值