刷题记录(1)

烦恼的高考志愿

题目背景

计算机竞赛小组的神牛 V 神终于结束了高考,然而作为班长的他还不能闲下来,班主任老 t 给了他一个艰巨的任务:帮同学找出最合理的大学填报方案。可是 v 神太忙了,身后还有一群小姑娘等着和他约会,于是他想到了同为计算机竞赛小组的你,请你帮他完成这个艰巨的任务。

题目描述

现有 m m m 所学校,每所学校预计分数线是 a i a_i ai。有 n n n 位学生,估分分别为 b i b_i bi

根据 n n n 位学生的估分情况,分别给每位学生推荐一所学校,要求学校的预计分数线和学生的估分相差最小(可高可低,毕竟是估分嘛),这个最小值为不满意度。求所有学生不满意度和的最小值。

输入格式

第一行读入两个整数 m , n m,n m,n m m m 表示学校数, n n n 表示学生数。

第二行共有 m m m 个数,表示 m m m 个学校的预计录取分数。第三行有 n n n 个数,表示 n n n 个学生的估分成绩。

输出格式

输出一行,为最小的不满度之和。

样例 #1

样例输入 #1

4 3
513 598 567 689
500 600 550

样例输出 #1

32

提示

数据范围:

对于 30 % 30\% 30% 的数据, 1 ≤ n , m ≤ 1000 1\leq n,m\leq1000 1n,m1000,估分和录取线 ≤ 10000 \leq10000 10000

对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 100000 1\leq n,m\leq100000 1n,m100000,估分和录取线 ≤ 1000000 \leq 1000000 1000000 且均为非负整数。

这题的解题思路应该是利用二分查找,暴力循环容易超时。
不过这题由于是要找到最接近的数而不是准确的值,所以要在原来的二分查找上稍作修改(做特判),尤其注意不能越界。
二分查找代码:

#include <iostream>
using namespace std;

int nums[101];

int Search_Bin(int left,int right,int n)
{
    int l = left;
    int r = right;
    int i;
    int mid = (l + r) / 2;
    if(l > r)
    return -1;
    if(nums[mid] == n)
    return mid;
    if(nums[mid] > n)
    {
        r = mid - 1;
        return Search_Bin(l,r,n);
    }
    if(nums[mid] < n)
    {
        l = mid + 1;
        return Search_Bin(l,r,n);
    }
    return 0;
}
int main()
{
    int n;
    cin >> n;
    int i;
    for(i = 0; i < n; i++)
    {
        cin >> nums[i];
    }
    int left = 0,right = n - 1;
    int mid = (left + right) / 2;
    int target;
    cin >> target;
    Search_Bin(left,right,target);
    cout << Search_Bin(left,right,target) << endl;
    return 0;
}

解题代码:

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

int score[1000010], school[1000010];

int Search_Bin(int left, int right, int key)
{
    int l = left;
    int r = right;
    if(l == r)
    return l;
    int mid;
    int index;
    if(l > r)
    return -1;
    while (l <= r)
    {
        mid = (l + r) / 2;
        if (school[mid] == key)
        {
            return mid;
        }
        if (school[mid] < key)
        {
            l = mid + 1;
        }
        if (school[mid] > key)
        {
            r = mid - 1;
        }
    }
    if(l > 0)
    {
        if(abs(key - school[l]) < abs(key - school[l - 1]))
        index = l;
        else
        index = l-1;
    }else{
        index = l;
    }
    return index;
}
int main()
{
    int n, m;
    cin >> n >> m;
    long long sum = 0;
    int i, j;

    for (i = 0; i < n; i++)
        cin >> school[i];

    for (i = 0; i < m; i++)
        cin >> score[i];

    sort(score, score + m);
    sort(school, school + n);

    int left, right;
    for (i = 0; i < m; i++)
    {
        left = 0;
        right = n - 1;
        Search_Bin(left, right, score[i]);
        sum += abs(score[i] - school[Search_Bin(left, right, score[i])]);
    }
    cout << sum << endl;
    return 0;
}

领地选择

题目描述

作为在虚拟世界里统帅千军万马的领袖,小 Z 认为天时、地利、人和三者是缺一不可的,所以,谨慎地选择首都的位置对于小 Z 来说是非常重要的。

首都被认为是一个占地 C × C C\times C C×C 的正方形。小 Z 希望你寻找到一个合适的位置,使得首都所占领的位置的土地价值和最高。

输入格式

第一行三个整数 N , M , C N,M,C N,M,C,表示地图的宽和长以及首都的边长。

接下来 N N N 行每行 M M M 个整数,表示了地图上每个地块的价值。价值可能为负数。

输出格式

一行两个整数 X , Y X,Y X,Y,表示首都左上角的坐标。

样例 #1

样例输入 #1

3 4 2
1 2 3 1
-1 9 0 2
2 0 1 1

样例输出 #1

1 2

提示

对于 60 % 60\% 60% 的数据, N , M ≤ 50 N,M\le 50 N,M50

对于 90 % 90\% 90% 的数据, N , M ≤ 300 N,M\le 300 N,M300

对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 1 0 3 1\le N,M\le 10^3 1N,M103 1 ≤ C ≤ min ⁡ ( N , M ) 1\le C\le \min(N,M) 1Cmin(N,M)

这一题的话使用二位前缀和,用一个数组将每一个位置的面积都存起来(该坐标是正方形右下角的坐标,所以输出的时候要注意格式),然后再将要求的地盘用面积去加减就可以得到(画图很容易看出来)。

#include <iostream>
#define max 2000
using namespace std;

int Loc[max][max];
int cnt[max][max];

int main()
{
    int n,m,l;
    cin >> n >> m >> l;

    if(n > max || m > max)
    return 0;

    int i,j,k;
    for(i = 1; i <= n; i++)//从1开始防止后续越界
    {
        for(j = 1;j <= m; j++)
        {
            cin >> Loc[i][j];
        }
    }
    for(i = 1; i <= n; i++)
    {
        for(j = 1;j <= m; j++)
        {
             cnt[i][j] = cnt[i - 1][j] + cnt[i][j-1] + Loc[i][j] - cnt[i-1][j-1];
             //二维前缀和
        }
    }

    long long Max = -1e15;
    int x,y;
    for(i = l; i <= n; i++)
    {
        for(j = l; j <=m;j++)
        {
            if(Max < (cnt[i][j] - cnt[i-l][j] - cnt[i][j-l] + cnt[i-l][j-l]))
            {                
                Max = (cnt[i][j] - cnt[i-l][j] - cnt[i][j-l] + cnt[i-l][j-l]);
                //画图理解
                x = i - l + 1;
                y = j - l + 1;
                //画图
            }
        }
    }
    // cout << "MAX is:" << Max << endl;
    cout << x << " " << y << endl;
    return 0;
}

Sale

题面翻译

Bob要去参加一次旧电视卖场,一共有n台电视出售,编号为i的电视的价格为 a i a_i ai。有些电视的价格是个负数,Bob最多会买m台电视,问Bob最多能赚到多少钱。

输入:

第一行两个整数 n , m ( 1 ≤ m ≤ n ≤ 100 ) n,m(1\leq m\leq n\leq 100) n,m(1mn100),为待出售的电视机的数目和Bob打算买的电视机的数目。第二行有n个整数,整数之间用空格分开,第i个整数 a i ( − 1000 ≤ a i ≤ 1000 ) a_i(-1000\leq a_i\leq 1000) ai(1000ai1000)为第i台电视机的价格.

输出:

输出只有一个数字,即Bob最多能赚到的钱。
Translated by @sounkix

题目描述

Once Bob got to a sale of old TV sets. There were $ n $ TV sets at that sale. TV set with index $ i $ costs $ a_{i} $ bellars. Some TV sets have a negative price — their owners are ready to pay Bob if he buys their useless apparatus. Bob can «buy» any TV sets he wants. Though he’s very strong, Bob can carry at most $ m $ TV sets, and he has no desire to go to the sale for the second time. Please, help Bob find out the maximum sum of money that he can earn.

输入格式

The first line contains two space-separated integers $ n $ and $ m $ ( $ 1<=m<=n<=100 $ ) — amount of TV sets at the sale, and amount of TV sets that Bob can carry. The following line contains $ n $ space-separated integers $ a_{i} $ ( $ -1000<=a_{i}<=1000 $ ) — prices of the TV sets.

输出格式

Output the only number — the maximum sum of money that Bob can earn, given that he can carry at most $ m $ TV sets.

样例 #1

样例输入 #1

5 3
-6 0 35 -2 4

样例输出 #1

8

样例 #2

样例输入 #2

4 2
7 0 0 -7

样例输出 #2

7

这题用贪心策略去做,我一开始没想明白,我觉得只要不为正数可以了,然后被一句话点醒,他是赚钱,能赚最大,所以要用一个数来存储他赚的最大值,再与下一个数比较看是赚钱还是亏钱,亏钱可以不要。

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

int Sale[1010];
int main()
{
    int m,n;
    cin >> n >> m;

    int i,j;    
    for(i = 0; i < n; i++)
    {
        cin >> Sale[i];
    }
    
    sort(Sale,Sale+n);
    int sum = 0;
    int min = 100001;
    int minSum = 0;
   for(i = 0; i < m;i++)
   {
        for(j = i; j < n; j++)
        {
            if(min > Sale[j])
            {
                min = Sale[j];
            } 
        }
        if(sum + min < minSum)
        {
            sum += min;
        }else{
            break;
        }
        minSum = sum;
        min = 1000001;
   }
    cout << -sum << endl;
    return 0;
}

Forbidden Integer

题面翻译

你需要构造一个正整数序列,满足:

  1. 对于 i i i a i ≤ k a_i\le k aik a i ≠ x a_i\not=x ai=x
  2. ∑ a i = n \sum a_i=n ai=n

如无法构造,输出 NO,否则输出 YES 后,输出序列长度与序列中的每一个数。

题目描述

You are given an integer $ n $ , which you want to obtain. You have an unlimited supply of every integer from $ 1 $ to $ k $ , except integer $ x $ (there are no integer $ x $ at all).

You are allowed to take an arbitrary amount of each of these integers (possibly, zero). Can you make the sum of taken integers equal to $ n $ ?

If there are multiple answers, print any of them.

输入格式

The first line contains a single integer $ t $ ( $ 1 \le t \le 100 $ ) — the number of testcases.

The only line of each testcase contains three integers $ n, k $ and $ x $ ( $ 1 \le x \le k \le n \le 100 $ ).

输出格式

For each test case, in the first line, print “YES” or “NO” — whether you can take an arbitrary amount of each integer from $ 1 $ to $ k $ , except integer $ x $ , so that their sum is equal to $ n $ .

If you can, the second line should contain a single integer $ m $ — the total amount of taken integers. The third line should contain $ m $ integers — each of them from $ 1 $ to $ k $ , not equal to $ x $ , and their sum is $ n $ .

If there are multiple answers, print any of them.

样例 #1

样例输入 #1

5
10 3 2
5 2 1
4 2 1
7 7 3
6 1 1

样例输出 #1

YES
6
3 1 1 1 1 3
NO
YES
2
2 2
YES
1
7
NO

提示

Another possible answer for the first testcase is $ [3, 3, 3, 1] $ . Note that you don’t have to minimize the amount of taken integers. There also exist other answers.

In the second testcase, you only have an unlimited supply of integer $ 2 $ . There is no way to get sum $ 5 $ using only them.

In the fifth testcase, there are no integers available at all, so you can’t get any positive sum.

这题是最头痛的一题,我最开始的想法是用一个数去不断加k,当大于n时减去一个k,同时k-1,重复这个操作,但是不知道为什么test2一直过不去,于是我去看了其他人的思路,在x!=1时始终有解,这是一种情况,x=1时要分k,k>=3的话看n是奇数还是偶数,如果n是偶数那就输出n/2个2就好了,如果n是奇数的话就要输出n/2-1个2再加上一个3,如果k=2,则看n,n是奇数就不能输出,如果n是偶数就可以输出n/2个2,最后还有个特判忘了就是当6 1 1那种情况的话(k = 1)这里也不能输出。

#include <iostream>
using namespace std;

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n,k,x;
        cin >> n >> k >> x;
        if(x != 1)
        {
            cout << "YES" << endl;
            cout << n << endl;
            for(int i = 0;i < n; i++)
            {
                cout << "1" << " ";
            }
            cout << endl;
        }else{
            if(k >= 3)
            {
                cout << "YES" << endl;
                cout << n/2 << endl;
                if(n % 2 != 0)
                {
                    for(int i = 0; i < n/2 - 1; i++)
                    {
                        cout << "2" << " ";
                    }
                    cout << "3" << " ";
                    cout << endl;
                }else{
                    for(int i = 0; i < n/2; i++)
                    {
                        cout << "2 ";
                    }
                    cout << endl;
                }
            }else if(k == 2)
            {
                if(n % 2 == 0)
                {
                    cout <<"YES" << endl;
                    cout << n/2 << endl;
                    for(int i = 0; i < n/2; i++)
                    {
                        cout << "2" << " ";
                    }
                }else{
                    cout << "NO" << endl;
                }
            }else if(k == 1)
            {
                cout << "NO" << endl;
            }
        }
    }
}

[ABC300D] AABCC

题面翻译

给定一个整数 N N N,统计 N N N 以内有多少数可以写成 a 2 × b × c 2 a^{2} \times b \times c^{2} a2×b×c2 的形式?其中, a , b , c a, b, c a,b,c 都是质数,且 a < b < c a < b < c a<b<c

题目描述

$ N $ 以下の正整数のうち、 $ a\ <\ b\ <\ c $ なる 素数 $ a,b,c $ を用いて $ a2 \times b \times c2 $ と表せるものはいくつありますか?

输入格式

入力は以下の形式で標準入力から与えられる。

$ N $

输出格式

答えを整数として出力せよ。

样例 #1

样例输入 #1

1000

样例输出 #1

3

样例 #2

样例输入 #2

1000000000000

样例输出 #2

2817785

提示

制約

  • $ N $ は $ 300\ \le\ N\ \le\ 10^{12} $ を満たす整数

Sample Explanation 1

$ 1000 $ 以下で条件を満たす整数は以下の $ 3 $ つです。 - $ 300\ =\ 22 \times 3 \times 52 $ - $ 588\ =\ 22 \times 3 \times 72 $ - $ 980\ =\ 22 \times 5 \times 72 $

这题我开始是用的埃氏筛但是过不去,后来改成了欧拉筛,然后看了一下别人是如何停止循环的思路,然后发现自己错是因为开始没有初始化代码导致的数据溢出。

#include <iostream>
#include <math.h>
using namespace std;
#define max 316228
long long int Isprime[max] = {0};
long long int prime[max] = {0};


int Euler()
{
    long long int cnt = 0;
    long long int i,j;
    Isprime[1] = 1;//特例
    for(i = 2; i < max; i++)
    {
        if(!Isprime[i])
        prime[++cnt] = i;
        for(j = 1; j <=cnt && i * prime[j] <= max; j++)
        {
            Isprime[i * prime[j]] = 1;
            if(i % prime[j] == 0)
            break;
        }
    }//欧拉筛
    return cnt;
}
int main()
{
    long long int n;
    cin >> n;
    long long int cnt = Euler();
    
    // for(int i = 0; i < n; i++)
    // {
    //     cout << prime[i] << endl;
    // }
    long long int count = 0;
    long long int a,b,c;
    for(long long int i = 1; i < cnt; i++)
    {
        a = prime[i];
        if(pow(a,4) > n)
        break;
        for(long long int j = i + 1; j < cnt; j++)
        {
            b = prime[j];
            if(a*pow(b,3) > n)
            break;
            for(long long int k = j + 1; k < cnt; k++)
            {
                c = prime[k];
                if((a*a*b*c*c) <= n)
                {
                    // cout << a*a*b*c*c;
                    count++;
                }else{
                    break;
                }
            }
        }
    }
    cout << count << endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值