Facebook Hacker Cup 2016 Round 2

Boomerang Decoration

处理前后缀,得到前缀和后缀染色任意长度所花的时间,然后枚举前缀和后缀染色个数取最优。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

char a[100010];
char b[100010];

int suf[100010];
int pre[100010];
int sans[100010];
int pans[100010];

int main(){
    int t;
    cin>>t;
    int cas = 0;
    while(t--){
        cas++;
        int n;
        cin>>n;
        scanf("%s",a+1);
        scanf("%s",b+1);

        suf[n]=1;
        pre[1]=1;
        for(int i=2;i<=n;i++){
            if(b[i]!=b[i-1])pre[i]=pre[i-1]+1;
            else pre[i]=pre[i-1];
        }
        for(int i=n-1;i>=1;i--){
            if(b[i]!=b[i+1])suf[i]=suf[i+1]+1;
            else suf[i]=suf[i+1];
        }

        memset(pans,0,sizeof(pans));
        memset(sans,0,sizeof(sans));

        for(int i=1;i<=n;i++){
            if(a[i]!=b[i]){
                pans[i] = pre[i];
            }else{
                pans[i] = pans[i-1];
            }
        }
        for(int i=n;i>=1;i--){
            if(a[i]!=b[i]){
                sans[i] = suf[i];
            }else{
                sans[i] = sans[i+1];
            }
        }

        int ans = max(sans[1],pans[1]);
        for(int i=1;i<n;i++){
            ans = min(ans,max(sans[i+1],pans[i]));
        }
        printf("Case #%d: %d\n",cas,ans);
    }
    return 0;
}

Carnival Coins

首先根据基本概率公式计算抛任意个硬币获胜的概率(我用了对数避免精度问题)。然后dp求解最优期望。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

double lg[3010];
double lgc[3010][3010];
double pp[3010];    
double dp[3010];


void init(){
    for(int i=0;i<=3000;i++){
        pp[i] = 0;
        dp[i] = 0;
    }
}

int main(){
    freopen("carnival_coins.txt","r",stdin);
    freopen("carnival_coins.out","w",stdout);

    for(int i=1;i<=3000;i++){
        lg[i]=log(i);
    }

    for(int i=1;i<=3000;i++){
        lgc[i][0] = 0;
        for(int j=1;j<=i;j++){
            lgc[i][j] = lgc[i][j-1]+lg[i+1-j]-lg[j];
        }
    }

    int t;
    cin>>t;
    int cas = 0;
    while(t--){
        init();
        cas++;
        int n,k;
        double p;
        cin>>n>>k>>p;

        for(int i=k;i<=n;i++){  //每次抛i个
            //计算抛i个win的概率
            double tmp = 0;
            if(p==0){
                pp[i] = 0;
            }else if(p==1){
                pp[i] = 1;
            }else{
                for(int j=k;j<=i;j++){  //抛i个,有j个向上 
                    tmp += pow(M_E,lgc[i][j]+log(p)*j+log(1-p)*(i-j) );
                }
                pp[i]=tmp;
            }
        }

        for(int i=1;i<=n;i++){
            for(int j=0;j<i;j++){
                dp[i] = max(dp[i],dp[j]+pp[i-j]);
            }

        }

        printf("Case #%d: %.9f\n",cas,dp[n]);
    }
    return 0;
}

Snakes and Ladders

只有高相同的梯子,且中间没有更高的梯子隔断,才能互相挂蛇。那些可以互相挂蛇的梯子,单独拿出来,一组一组计算。我们可以先将x坐标离散化,然后给梯子排序(先高低再左右),按高低从高到低处理。成为一组首先要同高,其次不能被之前更高的梯子隔断,处理过的梯子离散化后的x坐标放入树状数组中维护,就可以迅速查询是否被阻断。
以上方法可以完成梯子的分组,同组梯子两两之间都可以挂蛇,计算花费的时候,朴素的算法复杂度是 O(n2) 的,会超时,通过完全平方公式,可以推出一个 O(n) 的计算方法。大体思路是:假设当前处理的是第 i 个梯子,它和上一个梯子的距离是dxi=xixi1,考虑 dxi 作为完全平方的第二项时的展开式,递推维护好交叉项和第一项。具体见代码。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const ll mod = 1e9+7;

struct ladder{
    int x;
    int h;
    bool operator<(const ladder &other){
        if(h!=other.h){
            return h>other.h;
        }else{
            return x<other.x;
        }
    }
}lads[200010];

int c[200010];

vector<int> seg;

inline int lowbit(int x){
    return x&(-x);
}

void add(int x){
    while(x<200010){
        c[x]++; 
        x+=lowbit(x);
    }
}

int query(int x){
    int res = 0;
    while(x){
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}

map<int,int> mpx;

ll ans;
void init(){
    memset(c,0,sizeof(c));
    mpx.clear();
    ans=0;
}

vector<int> vec;

//处理同组 
void work(){
    int sz = seg.size();
    ll tleft = 0;
    ll tmid = 0;
    ll tmp = 0;
    for(int i=1;i<sz;i++){
        ll dx = seg[i] - seg[i-1];
        ll tright = (dx*dx)%mod*i%mod;
        tleft = tmp;
        tmp = tleft + 2*tmid*dx + tright;
        tmp%=mod;
        ans+=tmp;
        ans%=mod;
        tmid += dx*i;
        tmid%=mod;
    }

}

int main(){
//  freopen("snakes_and_ladders.txt","r",stdin);
//  freopen("snakes_and_ladders.out","w",stdout);
    int t;
    cin>>t;
    int cas = 0;
    while(t--){
        init();
        cas++;

        int n;
        cin>>n;

        for(int i=0;i<n;i++){
            scanf("%d%d",&lads[i].x,&lads[i].h);
            mpx[ lads[i].x ] = 0;
        }

        //离散化 
        int kk =1;
        map<int,int>::iterator it;
        for(it=mpx.begin();it!=mpx.end();it++){
            it->second = kk++;
        }

        sort(lads,lads+n);

        for(int i=0;i<n;i++){
            vec.push_back(lads[i].x);
            if(i==n-1 || lads[i].h != lads[i+1].h){
                //下面处理同高的
                int sz = vec.size();
                int leftMostX = mpx[vec[0]];
                int start = 0;

                for(int j=0;j<sz;j++){
                    int curX = mpx[vec[j]];
                    if(query(curX)!=query(leftMostX)){
                        work();
                        seg.clear();
                        leftMostX = curX;
                        start = j;
                    }
                    seg.push_back(vec[j]);
                }
                work();
                seg.clear();
                //同高的处理完了,作为障碍物插入BIT
                for(int j=0;j<sz;j++){
                    int target = mpx[vec[j]];
                    add(target); 
                } 
                vec.clear();
            }
        }
        printf("Case #%d: %I64d\n",cas,ans);
    }
    return 0;
}



Costly Labels

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值