2020-05-26 习题训练三

题目:Sorted Adjacent Differences

题目链接:https://vjudge.net/problem/CodeForces-1339B

思路: 

题目给出一个长度为n的数列,要求把这些数重新排序,使得 |a1a2≤ a2a3 ≤ … ≤ an1an | ,其实把数组按大小排序,可以知道

相距越远的两个数,两者的差越大,所以我们可以通过前后循环获取数,这样得到的数列,每两数之间的差则是逐渐减小的,所以最后倒着输出就行,

当时憨憨,直接输出了。

解题代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
using namespace std;
const long long N = 1e10 + 7;
const int maxn = 1e5 + 5;
const long long INF = 8e18;
typedef long long ll;
#define for0(i,n) for(int i = 0;i < n;i++)
#define for1(i,n) for(int i = 1;i <= n;i++)
using namespace std;

int x[maxn],b[maxn];

int main()
{
   int t;
   cin >> t;
   while(t--){
        int n,j = 0;
        cin >> n;
        for1(i,n){
          cin >> x[i];

        }
        sort(x+1,x+1+n);
        for(int i = 1;i <= n/2;i++){
            b[j++] = x[i];
            b[j++] = x[n-i+1];
        }
        if(n%2)
            b[j++] = x[n/2+1];
        for(int i = n-1;i >= 0;i--){
            cout << b[i] << " ";
        }
        cout << endl;

   }
   return 0;
}

题目:Powered Addition

题目链接:https://vjudge.net/problem/CodeForces-1339C

思路: 

  这道题就是寻找一个最小秒数 x ,可以通过在第m秒时( 1 <= m <= x )在数组中选择任意数加上2(m-1)  ,最后这个数列变为一个不减序列。

当数列本身就是不减序列时,当然x就等于0,而出现减小情况时,这时就肯定会存在一个最高端和最低端,当这个高度差都可弥补时,其他的高度差

当然也可填补,因为每一秒时可以任意选择哪些数加获不加。所以主要就是来寻找最高端和最低端的高度差(1 + 21 + 2 +    + 2x  这个数要大于等于这个高度差)。

解题代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
using namespace std;
const long long N = 1e10 + 7;
const int maxn = 1e5 + 5;
const long long INF = 8e18;
typedef long long ll;
#define for0(i,n) for(int i = 0;i < n;i++)
#define for1(i,n) for(int i = 1;i <= n;i++)
ll x[100100];
int main()
{
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        ll maxnum = -N ,sum = 0,time = 0,m = 0;
        for(int i = 0;i < n;i++){
            cin >> x[i];
        }
        for(int i = 0;i < n;i++){
            maxnum = max(maxnum,x[i]);
            m = max(m,maxnum - x[i]);

        }
        while(m - sum > 0){
            sum += pow(2,time++);
        }
        cout << time << endl;

    }
    return 0;
}

题目:Middle Class

题目链接:https://vjudge.net/problem/CodeForces-1334B

思路: 

  给出 n 个人的财富,并给出一个富人标准 x ,你可以收取一些人的钱然后平均分给这些被收取钱财的人手中,问最多可以创造多少名富人。

这个题一想就是先收有钱人的钱财,然后平分,不断更新富人数,当出现平均值低于富人标准时,往后便永远不会出现新答案。

解题代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
using namespace std;
const long long N = 1e10 + 7;
const int maxn = 2e5 + 5;
const long long INF = 8e18;
typedef long long ll;
#define for0(i,n) for(int i = 0;i < n;i++)
#define for1(i,n) for(int i = 1;i <= n;i++)
ll sum[100100];
int a[100100];

int main()
{
    int t;
    cin >> t;
    while(t--){
        int i,n,x,num = 0;
        cin >> n >> x;
        for(i = 1;i <= n;i++){
            cin >> a[i];
        }
        sort(a+1,a+n+1,greater<int>());
        for( i = 1;i <= n;i++){
            sum[i] = sum[i-1] + a[i];
            if(sum[i] * 1.0 / i < x)
                break;
        }
        cout << i - 1 << endl;
    }
    return 0;
}

题目:Circle of Monsters

题目链接:https://vjudge.net/problem/CodeForces-1334C

思路: 

  给出n个怪物(围成一圈)的血量和爆炸伤害,其中你可以用一颗子弹打掉一个怪物一滴血,当一个怪物死掉时,便发生爆炸,使得下一个怪物血量减少。问最少消耗的子弹数。这时可以找到选择的起始点不同,最后消耗的子弹也会不同,但每当起始点确定,肯定都是向一个方向进行,所以可以预先处理一下每个怪若被前一个怪炸掉后的血量(差分)这样可以得到一个全部怪被前一个怪炸的血量和,然而当选择一个怪物时这个怪不会被炸,所以再加上他之前怪的损伤,就得到答案。

解题代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
using namespace std;
const long long N = 1e18 + 7;
const int maxn = 1e5 + 5;
const long long INF = 8e18;
typedef long long ll;
#define for0(i,n) for(int i = 0;i < n;i++)
#define for1(i,n) for(int i = 1;i <= n;i++)
ll a[300100],b[300100],num[300100];
int main()
{
    int t;
    cin >> t;
    while(t--){
        int n;
        ll sum = 0,minnum = N;
        cin >> n;
        for0(i,n){
            scanf("%lld%lld",&a[i],&b[i]);
        }
        for0(i,n){
            if(i == 0)
                num[i] = max( (ll)0,a[i] - b[n-1]);
            else{
                num[i] = max( (ll)0,a[i] - b[i-1] );
            }
            sum += num[i];
        }
        for(int i = 0;i < n;i++){
            minnum = min( minnum,sum + (a[i] - num[i]) );
        }
        printf("%lld\n",minnum);
    }

    return 0;
}

 

题目:Kind Anton

题目链接:https://vjudge.net/problem/CodeForces-1333B

思路: 

给出两个数组a,b,数组a为由0,-1,1组成,你可以利用 ai 之前的数进行加法运算 ,问是否可以将 a 数组转换为 b数组。其实就是可以比较 ai 与 bi 的大小,看它之前是否出现了想要的数,可以用map统计,再从后往前遍历,而且先删除掉此时记录的ai的一次次数。

解题代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
using namespace std;
const long long N = 1e10 + 7;
const int maxn = 1e5 + 5;
const long long INF = 8e18;
typedef long long ll;
#define for0(i,n) for(int i = 0;i < n;i++)
#define for1(i,n) for(int i = 1;i <= n;i++)
int a[maxn],b[maxn];
map<int,int> ma;
int main()
{
    int t;
    cin >> t;
    while(t--){
        int n,findnum = 1;
        cin >> n;
        for(int i = 1;i <= n;i++){
            cin >> a[i];
            ma[a[i]]++;
        }
        for(int i = 1;i <= n;i++){
            cin >> b[i];
        }
        for(int i = n;i > 0;i--){
            ma[a[i]] --;
            if(a[i] < b[i]){
                if(ma[1] == 0){
                    findnum = 0;
                    break;
                }
            }
            if(a[i] > b[i]){
                if(ma[-1] == 0){
                    findnum = 0;
                    break;
                }
            }

        }
        if(findnum)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
        ma.clear();

    }
    return 0;
}

 

题目Eugene and an array

题目链接:https://vjudge.net/problem/CodeForces-1333C

思路: 

题目给出一个长度为n的数列,问又多少个子串,并且这些子串里面没有区间和为0的情况。这个题一看就需要预处理前缀和,要寻找区间和为0的区间,假设区间 [r , l ] 区间和为0, 则有sum[ l ] - sum[ r-1 ] = 0,即 sum[ l ] = sum[ r-1 ] ,这里你可以固定右端点,向左寻找可以取到的位置,而寻找左边能取到的位置,便是当前最大的区间和为0的左端点。

解题代码:

//        .--------------.
//        | Try First One|
//        '--------------'
//                |     .--------------.
//                |     |              |
//                V     V              |
//              .--------------.       |
//              |      AC.     |<---.  |
//              '--------------'    |  |
//              (True)|  |(False)   |  |
//           .--------'  |          |  |
//           |           V          |  |
//           |  .--------------.    |  |
//           |  |   Try Again  |----'  |
//           |  '--------------'       |
//           |                         |
//           |  .--------------.       |
//           '->| Try Next One |-------'
//              '--------------'
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
using namespace std;
const long long N = 1e10 + 7;
const int maxn = 2e5 + 5;
const long long INF = 8e18;
typedef long long ll;
#define for0(i,n) for(int i = 0;i < n;i++)
#define for1(i,n) for(int i = 1;i <= n;i++)

map<long long, int> r;//维护每个前缀和之前出现的最近位置(即这个区间和为0的左端点)
long long sum[maxn];
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> sum[i];
        sum[i] += sum[i - 1];
        r[ sum[i] ] = -1;
    }

    long long total = 0;
    int maxpoint = -1; //赋值为-1,是为了考虑开头的情况
    r[0] = 0;   //考虑到开头到某一位置为区间和为0的情况
    for (int i = 1; i <= n; i++)
    {
        if (r[ sum[i] ] != -1)
            maxpoint = max(maxpoint, r[ sum[i] ]); //遇到含区间和的情况更新左边界
        r[ sum[i] ] = i;
        total += i - (maxpoint + 1);//maxpoint 这个为前缀和区间左端下标  实际位置为maxpoint+1

    }

    cout << total << endl;
    return 0;
}

 

posted @ 2020-05-29 21:49  emhhbw==  阅读(187)  评论(0)    收藏  举报