Codeforces Round #653 (Div. 3)(A~E)

题目传送门

A. Required Remainder

思路

  • 题意
  1. 给我们n,x,y 的值 让我们找到 k%x==y的k最大值,0<=k<=n0<=k<=n
  • 分析
  1. 很水的一道题, 考虑n中包含x的数量为ct=n/xct=n/x, 我们肯定要把这些包含x全部用上, 才可以使k更大, 全部用上得到的k为 ctk+yct*k+y,但是我们要 特殊考虑 如果ct*k+y >n的话要使 答案变成 ct * k + y - x

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<cstdio>
#include<cmath>
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = s; i <= e; i ++)
using namespace std;

const int mxn = 2e5 + 10;
ll ar[mxn];

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int x, y, n;
        scanf("%d %d %d", &x, &y, &n);
        int t = n / x * x;
        int val = t + y;
        if(val > n)
            val -= x;
        printf("%d\n" ,val);
    }

    return 0;
}

B. Multiply by 2, divide by 6

思路

  • 题意
  1. 给我们一个数n,我们可以对其进行两种操作:
    1. 令 n *= 2
    2. 两 n /= 6(当 n%6==0的时候)
  2. 问最少经过多少次 操作 可以把 n 变成1 ?
  • 分析
  1. 首先我们想,如果n一直进行操作2.一直 n除以6的话,最后的结果得到一个1,这是最理想的,最少的操作次数,
  2. 我们可以把 让n除6这个操作 看成让n先除3,在除2, 那么我们假设n最多可以除以 x个3, 假设 n最多可以除以y个2(求x,y的过程用 因数分解,把n按因子2、3分解 如果最后分解出来剩下的数不是1的话,输出-1)
    1. 因为n实际上除的是6=3*2,所以 n 可以除以x个3,就要求最多只能被x个连续的2整除,所以如果y > x 的话,我们无论如何 都没法消去多的2yx2^{y-x}次方, 所以输入-1
    2. 而如果y < x 的话,我们可以通过 操作1 来增加n中包含2的数量,即:增加y的数量,令y与x 相等,此时x-y就是 要进行1操作的次数, 而x的数量就是 要进行操作2的次数, 两次数想加就是ans

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<cstdio>
#include<cmath>
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = s; i <= e; i ++)
#define rep_(i, e, s) for(int i = e; i >= s; i --)
using namespace std;

const int mxn = 2e5 + 10;
ll ar[mxn];
int br[5];

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        memset(br, 0, sizeof(br));
        int n;
        scanf("%d", &n);
        rep_(i, 3, 2)
        {
            while(n % i == 0)
            {
                br[i] ++;
                n /= i;
            }
        }

        if(n == 1)
        {
            if(br[3] < br[2])
                printf("-1\n");
            else
                printf("%d\n", br[3] - br[2] + br[3]);
        }
        else
            printf("-1\n");
    }


    return 0;
}


C. Move Brackets

思路

  • 分析
  1. 这题没啥说的,就是 stack 的经典应用题,答案就是 最后还在站内的字符的数量 / 2

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<cstdio>
#include<cmath>
#include<stack>
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = s; i <= e; i ++)
#define rep_(i, e, s) for(int i = e; i >= s; i --)
using namespace std;

const int mxn = 2e2 + 10;
char ar[mxn];

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n;
        scanf("%d", &n);
        scanf("%s", ar + 1);
        stack<char> st;
        for_(i, 1, n)
        {
           if(st.empty()) 
                st.push(ar[i]);
           else
           {
               if(st.top() == '(' && ar[i] == ')') 
                   st.pop();
               else
                   st.push(ar[i]);
           }
        }
        printf("%lu\n", st.size() / 2);
    }

    return 0;
}

D. Zero Remainder Array

思路

  • 题意
  1. 给我们一个一个长度为n 的序列a,现在我们要通过下面两种操作,使a中所有元素能够被k整除, 又给我们的一个变量x(初始值为0)

    1. a[i]+=x,x++a[i]+=x,x++,这个操作 对每个元素a[i]最多只能使用一次
    2. x++x++
  2. 问我们 最少需要 多少次上面的操作?

  • 分析
  1. 在a中元素中如果已经可以被k整除的话,我们不需要对他们进行操作,我们假设剩下的不能被k整的除的元素的形成的新数组b,对于b中的元素我们求出的每个b中元素bib_i距离k某个倍数差了多少,这些差值形成一个新的数组c。
    1. 举例:b :{1、1、4、 5} ,k = 3,对于b中每个元素bibi 减去 k 的某个倍数(这个倍数为(bi/k+1)k(b_i/k+1)*k)
    2. 之后得到c:{ 2,2,2,1}–>即:c:{1,2,2,2},
    3. 对于c中第一个元素1,我们需要先把x从0变为1(通过操作2),之后再通过一次 操作1 加到第一个元素1上,就是能使c中第一个数对应的在b中的元素可以被k整除了(之后x变为了1+1=2)
    4. 接着考虑c中第一个元素2,我需要 2 - x次第一种的操作,和1次第二种的操作,总结一下就是需要(cix+1c_i-x+1次两种操作,之后x=ci+1=2+1x=c_i+1=2+1),
    5. 接下来考虑c3=2c_3=2,这个时候我们发现x=3>2,两种操作都没有进行的意义了,这个时候我们只能无奈使c3c_3的值增大1*k(只要这样才可以付出,小的代价,而继续操作),令c_3+= k == 5,这样我们需要的进行的次数为53+1=35-3+1=3之后x变成了6,
    6. 当我们进行第四个元素的时候,发现x=6>2,这个时候的我们让 c4+=2kc_4+=2*k,这样又可以进行操作了
  2. 核心的过程就是这样,这个过程的中 特别注意的就是 对于c中重复的元素我们应该 不断的让重复的加上 不同的k的倍数 ,之后所有c中的元素就的各不相同了,我们就可以 for循环一遍求出 ans了

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<cstdio>
#include<cmath>
#include<stack>
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = (s); i <= (e); i ++)
#define rep_(i, e, s) for(int i = (e); i >= (s); i --)
using namespace std;

const int mxn = 2e5 + 10;
vector<ll> v;
vector<ll> res;

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        v.clear();
        res.clear();
        ll n, k;
        scanf("%lld %lld", &n, &k);
        ll t;
        for_(i, 1, n)
        {
            scanf("%lld", &t);
            if(t % k)
            {
                ll ct = t / k;
                ll val = k * (ct + 1) - t;
                v.pb(val);
            }
        }

        sort(v.begin(), v.end());
        pair<ll, ll> p;
        p.fi = -1, p.se = 0;

        for(int i = 0; i < v.size(); i ++)
        {
            if(v[i] != p.fi)
            {
                res.pb(v[i]);
                p.fi = v[i];
                p.se = 1;
            }
            else
            {
                res.pb(v[i] + k * p.se);
                p.se ++;
            }
        }
        sort(res.begin(), res.end());
        ll sum = 0;
        ll x = 0;
        for(auto s : res)
        {
            sum += (s - x + 1);
            x = s + 1;
        }

        printf("%lld\n", sum);
    }

    return 0;
}


E1. Reading Books (easy version)

思路

  • 题意
  1. 给我们n本书,每本书有三个参数 t、a、b,分别为:看这本书所需要的时间、a1表示 爱丽丝 喜欢这本书、b1表示 鲍勃 喜欢这本书
  2. 现在 他们两个人都要从n本书中选择k本喜欢的数,他们两个人选择的书 形成一个共享的集合(就是两个人 选择选择的书的种类的并集 ),最阅读的总时间为这个集合的 没种书阅读时间tit_i想加,
  3. 求这个最小时间,如果两个人都选择出k本喜欢的书,输出-1
  • 分析
  1. 这一题根据贪心,首先两个人选择的书的总种类越少越好,而且两个都应该只选k本喜欢的书,不能多选,
  2. 此外我们可以把:两本书(一本爱丽丝喜欢,另一本鲍勃喜欢,而且选择的这两本书的时间之和尽量小)看做一本新的书,这样 这本 新读书 阅读的总时间就要 原来的两本书的时间之和,,,这样我们不断的选择两本书,尽可能的多拼凑出新的书,这本新书两个人都喜欢
  3. 这样,我们 把所有 『拼凑出的书』和 所有原来 就已经被两个人同时喜欢的书 放在一起形成一个集合 S,从S中选择k本时间最短的书就是ans(当然如果S中书的数量<k 那么就是无解,输出-1)

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<cstdio>
#include<cmath>
#include<stack>
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = (s); i <= (e); i ++)
#define rep_(i, e, s) for(int i = (e); i >= (s); i --)
using namespace std;

const int mxn = 2e5 + 10;
queue<ll> q;
vector<ll> v;
int a[mxn];
int b[mxn];

int main()
{
    /* fre(); */
    ll n, k;
    scanf("%lld %lld", &n, &k);
    int t, x, y;
    int na = 0, nb = 0;
    for_(i, 1, n)
    {
        scanf("%d %d %d", &t, &x, &y);
        if(x == 1 && y == 1)
            v.pb(t);
        else if(x == 1 && y == 0)
            a[na ++] = t;
        else if(y == 1 && x == 0)
            b[nb ++] = t;
    }
    sort(a, a + na);
    sort(b, b + nb);
    /* for_(i, 0, na - 1) */
    /*     cout << a[i] << " "; */
    int ct = min(na, nb);
    for_(i, 0, ct - 1)
        v.pb(a[i] + b[i]);
    if(v.size() >= k)
    {
        sort(v.begin(), v.end());
        int sum = 0;
        for_(i, 0, k - 1)
            sum += v[i];
        printf("%d\n", sum);
    }
    else
    {
        printf("-1\n");
    }


    return 0;
}


剩下题的之后再补。。。。。。。。。。。。

©️2020 CSDN 皮肤主题: 像素格子 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值