暑假每日一题(四)


前言

每天进步一点点!


一、乘车问题(模拟)

题目链接

n 个班的小朋友乘大巴去郊游,第 i 个班有 ai 个人。

每隔一段时间就会来一辆空大巴车,每个大巴车可以容纳 m 个小朋友。

已知,在安排乘车时,必须按照 1 班,2 班,…,n 班的顺序,依次安排每个班的小朋友。

同一个班的小朋友必须被安排在同一辆车内。

也就是说,如果当前需要安排 i 班乘坐大巴,而此时大巴剩余的座位数量少于 ai,则让大巴先走,i 班以及后续班级共同等待下一辆大巴到来。

请问,将所有小朋友接走,共需多少辆大巴?

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含两个整数 n,m。

第二行包含 n 个整数 a1,a2,…,an。

输出格式
每组数据输出一行结果,表示所需大巴数量。

数据范围
1≤T≤30,
1≤n,m≤100,
1≤ai≤m
输入样例:
2
4 3
2 3 2 1
3 4
1 2 1
输出样例:
3
1

这道题没有算法,只有模拟,虽然如此,但是我写这道题的时候的思路有点混乱,不是很清晰,觉得y总的方法是真的不错哟!

#include <iostream>
#include <algorithm>
#include<cstring>
using namespace std;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        cin>>n>>m;
        int res=0,cur=0;
        while(n--)
        {
            int x;
            cin>>x;
            if(cur+x>m)res++,cur=0;
            cur+=x;
        }
        if(cur)res++;
        cout<<res<<endl;
    }
    return 0;
}

二、点

题目链接
给定一个平面上的 N 个点,请你计算所有点对之间距离的平方和。

输入格式
第一行包含整数 N,表示点的个数。

接下来 N 行,每行包含两个整数 X,Y,表示一个点的横纵坐标。

注意,不保证所有点的位置各不相同。

输出格式
输出所有点对之间距离的平方和。

数据范围
1≤N≤105,
−10000≤X,Y≤10000。

输入样例:
4
1 1
-1 -1
1 -1
-1 1
输出样例:
32

这是一个纯数学推导问题,就是将他的方程展开化简

在这里插入图片描述

#include <iostream>
#include <algorithm>
#include<cstring>

using namespace std;

typedef long long LL;
const int N=100010;
int n;
int x[N],y[N];

LL get(int x[])
{
    LL s1=0,s2=0;
    for(int i=0;i<n;i++)
    {
        s1+=x[i]*x[i];
        s2+=x[i];
    }
    return n*s1-s2*s2;
}
int main()
{
   scanf("%d",&n);
   for(int i=0;i<n;i++)
    scanf("%d%d",&x[i],&y[i]);
   cout<<get(x)+get(y)<<endl;
    return 0;
}

三、第k个除数

题目链接

给定两个整数 n 和 k,请你找到并输出能够整除 n 的第 k 小的正整数。

输入格式
一行,两个整数 n 和 k。

输出格式
输出能够整除 n 的第 k 小的整数。

如果不存在,则输出 −1。

数据范围
1≤n≤1015,
1≤k≤109。

输入样例1:
4 2
输出样例1:
2
输入样例2:
5 3
输出样例2:
-1

这里的数据都很大。
找n的所有约数,经典算法,可以使用试除法O(根号n)
在排序之后,然后找到第k小的数,这个时候还有一个函数nth_elementO(logn)

nth_element

nth_element(a,a+k,a+n),函数只是把下标为k的元素放在了正确位置,对其它元素并没有排序,当然k左边元素都小于等于它,右边元素都大于等于它,所以可以利用这个函数快速定位某个元素。

#include <iostream>
#include <algorithm>
#include<cstring>
#include<vector>

using namespace std;

typedef long long LL;

int main()
{
    LL n,k;
    cin>>n>>k;
    vector<LL>d;//来存放约束
    for(int i=1;i<=n/i;i++)
        if(n%i==0)
    {
        d.push_back(i);
        if(n/i!=i)
            d.push_back(n/i);
    }
    if(k>d.size())
        puts("-1");
     else{
        nth_element(d.begin(),d.begin()+k-1,d.end());
        cout<<d[k-1]<<endl;
     }
     return 0;
}

乘法比除法快!!i*i<n比i<n/i快好多呢!!!

四、交换相邻元素

题目链接

给定一个长度为 n 的数组 a1,a2,…,an。

该数组是一个 1∼n 的排列。

数组的前 n−1 个位置中,部分位置可以进行交换操作,将该位置的元素与后面相邻位置的元素进行互换。

交换操作的次序和次数均不限。

请你判断给定的数组能否通过交换操作变为一个升序数组。

输入格式
第一行包含整数 n。

第二行包含 n 个整数 a1,a2,…,an。

第三行包含一个长度为 n−1 的 01 字符串,第 i 个字符为 1 表示第 i 个位置可以进行交换操作,第 i 个字符为 0 表示第 i 个位置无法进行交换操作。

输出格式
给定的数组可以通过交换操作变为一个升序数组则输出 YES,否则输出 NO。

数据范围
2≤n≤2×105,
1≤ai≤n,ai 两两不同。

输入样例1:
6
1 2 5 3 4 6
01110
输出样例1:
YES
输入样例2:
6
1 2 5 3 4 6
01010
输出样例2:
NO

维护最大区间,只要他的最大值和下标相等就可以啦!

#include <iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=200010;
int a[N];
char s[N];

int main()
{
    int n;
    bool flag=true;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
   scanf("%s",s+1);//这个方法很好哦!但是只适用于char哦!
    for(int i=1,t=0;i<=n;i++)
    {
        t=max(t,a[i]);
        if(s[i]=='0'&&t!=i)
            flag=false;
    }
    if(!flag)
        puts("NO");
    else puts("YES");
    return 0;
}

五、战舰

题目链接
给定一个 n×n 的字符矩阵,表示一片海域。

矩阵中 # 表示暗礁区域,. 表示安全区域。

现在要将一个 1×k 的战舰投放到海域中。

投放时,战舰不可接触到暗礁区域。

战舰可以横着投放,也可以竖着投放。

在投放完成后,每个安全区域要么包含战舰的一部分,要么不包含。

对于某个安全区域,如果所有可能的投放方式中,共有 m 种不同的投放方式,满足该区域包含战舰的一部分,那么就称该区域的投放指数为 m。

请确定投放指数最大的安全区域的位置坐标。

输入格式
第一行包含两个整数 n 和 k。

接下来 n 行,每行包含一个长度为 n 的字符串,表示海域。

输出格式
输出投放指数最大的安全区域的行、列坐标。

行从上到下,从 1 开始计数,列从左到右,从 1 开始计数。

如果答案不唯一,输出任意合理方案均可。

如果海域中根本无法投放战舰,则输出任意区域均可。

数据范围
1≤k≤n≤100
输入样例1:
4 3
#…#
#.#.

.###
输出样例1:
3 2
输入样例2:
10 4
#…##…
.#…#…
…#…#…#.
…#.#…
.#…##.#…
…#…#
…#.##…
.#…#.#…
…#…#.
…#.#…#
输出样例2:
6 1
输入样例3:
19 6
##…###
#…#####…##
…#########…
…###########…
…#############…
…###############…
.#################.
.#################.
.#################.
.#################.
#####…##…####
####…###
####…###
#####…####…####
.#####…####…#####
…###…###…
…###########…
…##…
#…#
输出样例3:
1 8

由于这道题的数据范围并不是很大,所以可以用很暴力的算法来写,然后呢,这道题就是要注意他的导入方式,一行行的读入,是从下标为1开始。

#include <iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=110;

char a[N][N];

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%s",a[i]+1);
    int x=1,y=1,res=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
    {
        if(a[i][j]=='#')continue;
       int l=j,r=j;
       while(l>=1&&a[i][l]=='.'&&j-l+1<=k)l--;
       while(r<=n&&a[i][r]=='.'&&r-j+1<=k)r++;
       int t=max(0,r-l-k);
         l=i,r=i;
         while(l>=1&&a[l][j]=='.'&&i-l+1<=k)l--;
         while(r<=n&&a[r][j]=='.'&&r-i+1<=k)r++;
         t+=max(0,r-l-k);
         if(t>res)
            {
                res=t;
                x=i,y=j;
            }
    }
    printf("%d %d\n",x,y);
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值