Codeforces Round #552 (Div. 3) A B C D E F G (暴力,dp,模拟)

10 篇文章 0 订阅
8 篇文章 0 订阅

题目链接:https://codeforces.com/contest/1154

A:Restoring Three Numbers

B:Make Them Equal

C:Gourmet Cat

D:Walking Robot

E:Two Teams

F:Shovels Shop

G:Minimum Possible LCM

A:给定b-a、a+c、b+c、a+b+c的值 求abc的值  (排序,做差求一下)

B:给定一个数组,现在有一个操作:对于数组的某个元素,你可以加或者减D(仅一次)。任务是将数组的所有值变成一样的。输出D的值,不存在输出-1。

放set里去重一下,是>3就-1,== 1 就是 0 , == 2,就是平均数做差,== 3,头尾搞一下就可以了,还要特判一下不相等,代码不放了。。。

C 你有只猫,周一、四、日吃鱼,周二、六吃兔肉。其余时间吃鸡肉。现在你要去旅行,且你准备了a份鱼、b份兔肉、c份鸡肉。求你在某天出门后这只猫能吃的的最大天数。(这个天数跟你周几出门有关

23333,这个题本来想抢一血的,结果我枚举的,忘了初始化,debug半天,wa4,改了就A了,就是取个Min,然后瞎判断一下,代码写的比较丑,就不放了。

D  有个机器人在0位置处,现在要走到位置n。机器人现在有一个电池容量为a,还有一个蓄电池容量为b(一开始都是满的)。数组的值代表此处有没有光照。走一格耗1电量,如果机器人使用电池行走并在太阳下时,蓄电池电量+1.(不能超过容量),求最远的行走距离 (我半天a和b搞反了,以至于自己花了40分钟才过这个傻逼题),当是1的时候,我们优先花可以不充电的电池,让可以充电的电池尽量充电,充满了就花不可以充电的(还要处理一下电池满的情况),是0的话就优先花可以充电的,

代码:(写的丑,勿喷。。。)

for(int i = 1; i <= n; i++) {
    if(c[i]) {
        if(b) {
            if(a == x) a--;
            else {
                b--;
                if(a < x)
                    a++;
            }
        } else {
            if(a) a--;
            else {
                ans = i - 1;
                break;
            }
        }
    } else {
        if(a) {
            a--;
        } else {
            if(b) {
                b--;
            } else {
                ans = i - 1;
                break;
            }
        }
    }
    if(a == 0 && b == 0) {
        ans = i;
        break;
    }
//            cout << a << "  " << b << endl;
}
cout << ans << endl;

E  有两个教练来选人,第一个先选。两个人选的策略是:找到还没被选的最大的一个。然后在选择它左边k个和右边k个。他们轮流选直到全部选完。输出他们都被谁选了

呃呃,直接链表模拟,赛后才过,一年没写数组模拟链表,debug了一个小时。。。菜的一匹,,,(注意最大值记录一下排名,不然会T)


ll  n,k;
int a[maxn],l[maxn],r[maxn],ans[maxn],vis[maxn];
int main() {
    ios::sync_with_stdio(false);
    while(cin >> n >> k) {
        set<int>s;
        for(int i = 1; i <= n; i++){
            cin >> a[i],l[i] = i - 1,r[i] = i + 1;
            vis[a[i]] = i;
            s.insert(a[i]);
        }
        MS1(ans);
        int id = 0, op = 1,num = 0;
        while(1){
            int Max = 0;
            int id = vis[*s.rbegin()];
            int ll = l[id],rr = r[id];
            for(int i = r[id],cnt = 1;i <= n  && cnt <= k;cnt++,i = r[i],rr = i){
                ans[i] = op;
                num++;s.erase(a[i]);
            }
            for(int i = l[id],cnt = 1;i >= 1 && cnt <= k ;cnt++,i = l[i],ll = i){
                ans[i] = op;
                num++;s.erase(a[i]);
            }
            ans[id] = op;
            for(int i = r[id],cnt = 1;i <= n && cnt <= k;cnt++){
                int x = r[i];
                r[i] = rr;l[i] = ll;
                i = x;
            }
            for(int i = l[id],cnt = 1;i >= 1 && cnt <= k ;cnt++){
                int x = l[i];
                r[i] = rr,l[i] = ll;
                i = x;
            }
            l[id] = ll,r[id] = rr;
            r[ll] = rr,l[rr] = ll;s.erase(a[id]);
            num++;
            if(num == n) break;
            op ^= 1;
        }
        for(int i = 1;i <= n;i++) if(ans[i])cout << ans[i]; else cout << 2;
        cout << endl;
    }
    cerr << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

F  你现在要买k把铲子,商店有n把铲子,价格数组给出。现在有m个优惠:如果一次买了x_i个铲子,那么其中前y_i个最便宜的铲子免费。一次只能使用一个优惠或者不使用。求最少花费。

首先我们可以排序,做个前缀和,可以跑个背包,f_i代表前i个铲子所需要的最少花费。

然后再枚举每个优惠使用情况

转移可以有f[i] = min(f[i - p[i].fi] + s[i] - s[i - p[i].fi + p[i].se],f[i]) 前面的部分很容易理解,背包的模型,后面

首先f[i - p[i].fi] 就是 3 部分 ,我们知道如果买fi个,前se可以免费,而我们要加的是1部分,那怎么求呢

就是s[i] - s[i - p[i].fi + p[i].se],可以求到,s[i - p[i].fi + p[i].se]就是 2 和 3部分的和

 


ll c,n,k,m;
P p[maxn];
ll a[maxn],f[maxn],s[maxn];///fi代表买i个铲子的最小花费。
int main() {
    ios::sync_with_stdio(false);
    while(cin >> n >> m >> k){
        for(int i = 1;i <= n;i++) cin >> a[i];
        sort(a + 1,a + 1 + n);
        for(int i = 1;i <= n;i++) s[i] = s[i - 1] +a[i];
//        for(int i = 1;i <= n;i++) cout <<a[i] << " ";
//        cout << endl;
//        for(int i = 1;i <= n;i++) cout <<s[i] << " ";
//        cout << endl;
        for(int i = 1;i <= n;i++) f[i] = s[i];
        for(int i = 1;i <= m;i++){
            cin >> p[i].fi >> p[i].se;
        }
        for(int i = 1;i <= k;i++){
            for(int j = 1;j <= m;j++){
                if(i >= p[j].fi)
                f[i] = min(f[i - p[j].fi] + s[i] - s[i - p[j].fi + p[j].se],f[i]);

            } 
        }
        cout <<f[k] << endl;
    }
    cerr << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

G  给定数组,求其中lcm(a,b)的最小的a和b的位置。

呃呃,这个题可以参考以前做的  https://blog.csdn.net/qq_38185591/article/details/88293190,同样的方法,用筛法搞一下,cf确实能跑1e7的n*log的,而且开了4s,枚举gcd,然后倍数超过2了就直接更新一下,按题中要求找最小的。还要再处理一下重复的地方。

ll vis[maxn];
map<ll,ll>m;
int main() {
    ios::sync_with_stdio(false);
    while(cin >> n){
        m.clear();
        ll Max = 0;
        ll anss = 1e18;
        vector<ll>ans,ansss;
        for(int i = 1;i <= n;i++){
            ll x;
            cin >> x;
            if(vis[x]){
               if(x < anss){
                   ansss.clear();
                   ansss.push_back(vis[x]);
                   ansss.push_back(i);
                   anss = x;
               }
            }
            vis[x] = i;
        }
        for(ll i = 1;i <= 1e7;i++){
                ans.clear();
            for(ll j = i;j <= 1e7;j += i){
                if(vis[j]) ans.push_back(j);
                if(ans.size() >= 2) break;
            }
            if(ans.size() >= 2){
                ll Max = ans[0] * ans[1] / i;
                if(Max < anss){
                    anss = Max;
                    ansss.clear();
                    ansss.push_back(vis[ans[0]]);;
                    ansss.push_back(vis[ans[1]]);
                }
            }
        } 
        sort(ansss.begin(),ansss.end());
        for(auto d:ansss) 
            cout << d << " ";   
    }
    cerr << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值