Codeforces Round #380 (Div. 1, Rated, Based on Technocup 2017 - Elimination Round 2)

  比赛的时候过了3题的pretest,结果systest怒跪2题。。rank几乎垫底。但是这场题目确实比较简单。

A. Road to Cinema

  cf特别爱出的二分题。。二分汽油容量,得到一个最小的能跑完的容量,然后在满足这个最小值的车里面找最便宜的。注意可能全程加速也赶不上。

#include <bits/stdc++.h>

using namespace std;

#define ll long long


const int maxn = 200010;

const ll INF = 1e18;

ll c[maxn];
ll v[maxn];

ll g[maxn];

ll n,k,s,t; //车数 加油站数 路程 时间

bool judge(ll x){
    ll Time = 0;
    for(int i=0;i<=k;i++){
        ll distance = g[i+1] - g[i];
        if(distance > x){
            return 0;
        }

        ll tmp = x - distance;
        tmp = min(distance,tmp);

        Time += tmp + (distance-tmp)*2;

        if(Time > t){
            return 0;
        }
    }

    if(Time > t){
        return 0;
    }else{
        return 1;
    }

}

ll bs(){
    ll l = 1;
    ll r = 4e9+10;
    ll res = -1;
    while(l<=r){
        ll mid = (l+r)>>1;
        if(judge(mid)){
            res = mid;
            r = mid - 1;
        }else{
            l = mid + 1;
        }
    }
    return res;
}

int main(){

    cin>>n>>k>>s>>t; 

    for(int i=1;i<=n;i++){
        scanf("%I64d %I64d",&c[i],&v[i]);
    } 

    for(int i=1;i<=k;i++){
        scanf("%I64d",&g[i]);
    }


    sort(g+1,g+k+1);
    g[0] = 0;
    g[k+1] = s;


    ll MIN = bs();

    ll res = INF;
    for(int i=1;i<=n;i++){
        if(v[i]>=MIN){
            res = min(res,c[i]);
        }
    }

    if(res == INF || MIN == -1){    //注意有可能全程加速也不行 
        cout<<-1<<endl;
    }else{
        cout<<res<<endl;
    }

    return 0;
}

B. Sea Battle

  贪心。我的写法是把所有船安排在尽可能靠右的位置,然后从左往右射击,这样就能模拟最坏情况。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

char s[200010];

int main(){

    int n,a,b,k;
    cin>>n>>a>>b>>k;  //长度 个数 船长度 

    scanf("%s",s+1);

    int cnt = 0;
    int leftMost = -1;
    int ship = 0;
    for(int i=n;i>=1;i--){
        if(s[i] == '0'){
            cnt++;
        }else{
            cnt = 0;
        }
        if(cnt == b){
            cnt = 0;
            ship++;
        }
        if(ship == a){
            leftMost = i;
            break;
        }
    }

    vector<int> hit;

    cnt = 0;
    int ans = 0;

    for(int i=1;i<=n;i++){
        if(s[i] == '0'){
            cnt++;
        }else{
            cnt = 0;
        }
        if(cnt == b){
            if(i<leftMost){
                ans++;
                hit.push_back(i);
                cnt = 0;
            }else{
                ans++;
                hit.push_back(i);
                break;
            }
        }
    }

    cout<<ans<<endl;

    for(int i=0;i<hit.size();i++){
        printf("%d ",hit[i]);
    }

    return 0;
}

C. Subordinates

  还是贪心。首先保证chief没有上司,然后统计上司个数为 i 的人数。然后要保证除了chief都有上司,即修改上司数为0的人,使得尽可能连续存在上司个数为0,1,2,3,…的人。然后枚举上司最多的人的上司数目,得到答案。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int maxn = 200010;

int a[maxn];

int f[maxn];

int miss[maxn];
int sum[maxn];

int main(){
    int n,s;
    cin>>n>>s;

    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }

    int ans1 = 0;

    if(a[s] != 0){
        ans1 ++;
        a[s] = 0;
    }

    int zero = 0;
    for(int i=1;i<=n;i++){
        f[a[i]] ++;
        if(a[i] == 0){
            zero ++;
        }
    }

    zero--;

    int i = 0;

    while(zero--){
        while(f[i]!=0){
            i++;
        }
        f[0]--;
        f[i]++;
        ans1++;
    }

    sum[0] = 1;
    for(int i=1;i<n;i++){
        if(f[i] == 0){
            miss[i] = miss[i-1] + 1;
        }else{
            miss[i] = miss[i-1];
        }
        sum[i] = sum[i-1] + f[i];
    }

    int ans2 = 1e9;

    for(int i=n-1;i>=1;i--){    //枚举上司最多的人的上司数 
        int tmp = max( (n-sum[i]) , miss[i] );
        ans2 = min(ans2,tmp);
    }

    if(n==1){
        ans2 = 0;
    }

    cout<<ans1+ans2<<endl;
    return 0;
}

D. Financiers Game

  首先要正确理解题意,就是两个人都想让自己拿到的总数尽可能大。容易想到应当用dp来做。状态dp(l,r,k,who)表示当前剩余的区间是 [l,r] ,上一步对手拿了 k 个数,当前轮到玩家who行动。但是这样的状态会爆内存。先确定 k 那一维大小开70足够,who那维开2。至于 l r,分析题意,我们可以发现当后手玩家行动后,后手玩家取的总个数一定不会比先手玩家少。于是我们用后手比先手多取的个数 R 代替r,这样 l 开2100,R开70足够。具体见代码。写成记忆化搜索比较容易实现。

#include <bits/stdc++.h>
#include <unordered_map>

using namespace std;

#define ll long long

int n;
int a[4004];

int sum[4004];

bool vis[2080][70][70][2];
int dp[2080][70][70][2];


int getSum(int l,int r){
    return sum[r] - sum[l-1];
}

int solve(int l,int R,int k,bool who){
    int r;
    if(who == 0){
        r = n-l+1 -R;
    }else{
        r = n-l+1 +k-R;
    }

    if(r-l+1<k){
        return 0;
    }

    if(vis[l][R][k][who]){
        return dp[l][R][k][who];
    }

    vis[l][R][k][who] = 1;

    int res;
    if(who == 0){   //max
        int t1 = solve(l+k,R,k,!who);
        if(r-l+1>=k+1){
            int t2 = solve(l+k+1,R,k+1,!who);
            if( (-t1+getSum(l,l+k-1)) > (-t2+getSum(l,l+k)) ){
                res = -t1+getSum(l,l+k-1);
            }else{
                res = -t2+getSum(l,l+k);
            }
        }else{
            res = -t1+getSum(l,l+k-1);
        }
    }else{          //min
        int t1 = solve(l,R,k,!who);
        if(r-l+1>=k+1){
            int t2 = solve(l,R+1,k+1,!who);
            if( (-t1+getSum(r-k+1,r)) > (-t2+getSum(r-k,r)) ){
                res = -t1+getSum(r-k+1,r);
            }else{
                res = -t2+getSum(r-k,r);
            }
        }else{
            res = -t1+getSum(r-k+1,r);
        }
    }

    dp[l][R][k][who] = res;
    return res;
}

int main(){
    cin>>n;

    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum[i] = sum[i-1] + a[i];
    }

    int ans = solve(1,0,1,0);
    cout<<ans<<endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值