「Codeforces」 #645 div2

A. Park Lighting在这里插入图片描述
题目概述:

给定一个n x m的矩阵,现在有一种灯能照亮相邻的两个格子,问最少有多少盏灯可以照亮全部的矩阵。

问题解析:

首先想到如果n x m为奇数,那么肯定至少有一个灯只贡献了一个格子的光。即一个灯和另一个灯同时照亮了一个格子,重复了。不过这是不可避免的。
而如果n x m为偶数,那么理论上最好情况是每个灯都可以照亮两个格子,没有浪费。

问题的解决:

首先想到只有一行的情况(同只有一列),那么只需要将灯顺序排列下去即可。  

如果有奇数的格子的话:
在这里插入图片描述
那么最后一个格子还需要一盏灯,不过这是无法避免的。

	 可以看出,对于1 x m 的情况,这种方法一定是最优的。
	 现在我们的目的就是将	n  x m 的矩阵降维到1 x m 。

可以使用这种方法:

对于 n>=2的矩阵,每两行都将灯竖直放置

在这里插入图片描述

那么最后只会剩余1行或者直接填满————>这两种情况
  1. 当只剩一行时:
    在这里插入图片描述
    即降维到了1 x m的情形。运用上述的1维方法。即可。
    这种情况下是不是肯定是最优情况呢?
    我们知道对于这种情况最后只会有两种情况:

     a.剩一个格子,这样浪费了一个。
     b.不会剩格子,不会浪费。
    

    对于b,不会浪费肯定是最优解。
    对于a,当浪费一个灯时,说明n x m是奇数,最优解也是浪费一个灯。
    当没有浪费灯时,说明是最优解。

  2. 当一行不剩时,很明显一盏灯都没有浪费,肯定是最优情况。

    所以此方法可行!
    等等。。。我是不是默认了n x m为奇数就是浪费一个灯,n x m为偶数就没有浪费灯?
    就是 (n x m+1) / 2就好了?
    交了一下,ac了。。。。。。。。。。。。我。。

(n x m+1)/2 代码

#include <iostream>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int a,b;
        cin >>a >> b;
        cout<<(a*b+1)/2<<endl;
    }


    return 0;
}

原思路代码:

#include <iostream>
using namespace std;
 
int f(int x,int y){
    int big=max(x,y),sma=min(x,y);
    if(sma==1) return (big+1)/2;
    if(sma==0) return 0;
    return f(big-2,sma)+sma;
 
 
}
 
int main(){
    int t;
    cin>>t;
    while(t--){
        int a,b;
        cin>>a>>b;
         int ans = f(a,b);
         cout<<ans<<endl;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
    }
    return 0;
}

B. Maria Breaks the Self-isolation
在这里插入图片描述
题目概述:

庭院的主人想宴宾客,但是每个宾客都有自己的社恐人数,如果除了他自己之外的庭院人数小于社恐人数那么他就不会进入庭院。给定所有的宾客的社恐值,问最多可以宴请多少宾客。

题目解析:

看题面,很容易想到对于社恐值小 的宾客,不应该让他在社恐值大的宾客后进入庭院。因为这样社恐值大的宾客会面临相比(社恐值小先入社恐值大后入)的方式更少的庭园人数。这样绝对不是最优情况。
所以首先按照社恐值来进行排序,先处理值小的人,再处理值大的人。

接下来是问题解决的关键:
对于所有进入方式来说,== 大家一起进入是最优的进入方式 ==,因为这样对于每个人来说 ***庭院人数+同时进入 的人数是所有方式最多的。
举个例子,如果n个人进入只有1个人的庭院,如果是分别进入的方式,那么第1个人面临的
庭院人数+同时进入 (除了他自己***的人数只有1,第二个人只有2,第三个人有3…以此类推。只有第n个人为n.

而如果同时进入的话,每个人面临的人数都为n,是最优的。

问题解决:

所以我们的问题现在只需要找到一次进入庭院的前k个人,使k最大即可。

可以遍历k,找到可行的k中最大的k。
因为需要k为最大值,所以要从后往前遍历k。找到可行的k就输出。

那么 ‘可行’ 是怎么判定呢?

只要保证庭院人数+同时进入-1>=每个人的社恐值,即可。
又因为庭院人数+同时进入-1=k,使k>=最大的社恐值,那么就可以进入了。
例如:
在这里插入图片描述
从k=6开始向前遍历,发现a[i]=9>k=6,所以不可以前6个人同时进入。
k=5时,发现a[i]=5 = k=5,所以可以前5个人同时进入。
所以不需要再向前遍历,输出5+1个人即可。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main() {
    int t;
    cin>>t;
    int a[100100];
    while(t--){
        int n;
        cin>>n;
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        sort(a,a+n);
        for(int i=n-1;i>=0;i--) {
            if(i+1>=a[i]) {
                cout<<i+1+1<<endl;
                break;
            }
            if(i==0&&i+1<a[i]) cout<<"1"<<endl;

        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值