Codeforces Round #725 (Div. 3)题解

Problem - A - Codeforces

题目大意:给定一个数组,你每次可以从左边取一个数字,或者从右边取一个数字,求取得序列中最大值和最小值所需的最小次数.
思路:简单模拟就是了,一共有三种取法,从左向右取完,从右向左取完,两边都取,主要用swap来简化过程.

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int t, n;
int a[105];

int main(){
    cin>>t;
    while(t--){
        cin>>n;
        int mindata = 105, maxdata = 0, minindex = 0, maxindex = 0;
        for (int i = 1; i <= n; i++){
                cin>>a[i];
                if (mindata > a[i]){
                    mindata = a[i];
                    minindex = i;
                }
                if (maxdata < a[i]){
                    maxdata = a[i];
                    maxindex = i;
                }
        }
        if (minindex > maxindex)swap(minindex,maxindex);
        int left = minindex;
        int right = n-maxindex+1;
        cout << min(left+right, min(left + maxindex-minindex, right + maxindex-minindex)) <<endl;
    }

    return 0;
}

Problem - B - Codeforces

题目大意:给定一个序列,你可以选取任意k个元素,将它们的数字个数,任意的分给所有的元素,求出最小的k使得序列的每个数都相等,如果不存在k输出-1.
思路:直接求平均值就可以,当无法被整除的时候,就是无解的情况.大于平均值的数字都会被进行分发.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAX = 2e5+5;
ll a[MAX];
int t, n;
long long temp;

int main(){
    cin>>t;
    while(t--){
        cin>>n;
        for (int i = 0; i < n; i++){
            cin>>a[i];
            temp+=a[i];
        }
        if (temp % n != 0){
            cout <<-1 <<endl;
        }else{
            long long avg = temp / n;
            int num = 0;
            for (int i = 0; i < n; i++){
                if (a[i] >avg){
                    num++;
                }
            }
            cout << num <<endl;
        }
        temp = 0;
    }

    return 0;
}

Problem - C - Codeforces

题目大意:给定一个序列,求出有多少组数对ai, aj满足i < j 且 l <= ai + aj <= r.
思路:读题的时候没看懂,直接跳了,以为是要求满足顺序下的数对个数,直接卡住,后来发现i和j大小关系的限制,只是为了防止数对重复出现一次.比较简单的题目,二分加排序,先把数组排个序,对于序列中的每个数,二分查找l-cur和r-cur+1的边界,两者直接相减就可以得到对于某个数符合的个数.

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int t, n;
const int MAX = 2e5+5;
ll b[MAX];

ll cal(ll cur){
    ll ans = 0;
    for (int i = 1; i < n; i++){
        int index = lower_bound(b, b+i, cur-b[i]) - b;
        if (i > index)ans += (i-index);
    }
    return ans;
}

int main(){
    cin>>t;
    while(t--){
        long long r, l;
        cin>>n>>l>>r;
        for (int i = 0; i < n; i++)cin>>b[i];
        sort(b, b+n);
        cout << cal(l) - cal(r+1) <<endl;	//lower_bound查找的包括=的情况,所以在查找右边界的时候要查找>=r+1

    }

    return 0;
}

Problem - D - Codeforces

题目大意:给定a, b, k三个数,你可以选择任意数n,保证a或者b可以被n整除,然后使a/=n,或b/=n,求能否使用恰好k次操作,使得a=b.
思路:直接求两个数的最大可能的操作数,就是求a,b的质因数个数,如果k大于这个质因数个数,那么无论如何也无法恰好取得k,但如果k<质因数个数,只需要将若干个质因数相乘放在一次操作里,就可以对操作次数进行压缩.题目还需要对k=1的情况进行特判,如果两数相等一定不符合,如果一个数可以被另一个数整除,那么是符合答案的.
这里提一下,想出来了做法还不一定有用,这题时间卡的很紧,因为测试数据量不小,比较好的方式是写一个素数筛,但是如果只筛到1e5, 后面的质数有晒不掉的可能,所以需要特判当前数是否为1,如果不是那么就是质数.反正这道题比较怪,用素数筛需要加特判,如果直接硬枚举得话,时间卡的紧,但是优化优化也能过.

#include<bits/stdc++.h>
using namespace std;


int a, b, k;
int num;
int t;
inline int read(){
    int ans = 0;
    char last = ' ', ch = getchar();
    while(ch<'0'|| ch>'9')last = ch, ch = getchar();
    while(ch>='0'&&ch<='9')ans = ans*10+ch-'0', ch = getchar();
    if (last == '-')ans=-ans;
    return ans;
}

vector<int>prime;
bool isprime[1000005];

int main(){
    for (int i = 2; i <= 1000000; ++i){
        if (!isprime[i]){
            prime.push_back(i);
        }
        for (int x : prime){
            if (x*i > 1000000)break;
            isprime[x*i] = true;
            if (i % x == 0)break;
        }
    }
    cin>>t;
    while(t--){
        a=read(), b = read(), k= read();
        int temp1 = a, temp2 = b;
        num = 0;
        for (int i = 0; prime[i] * prime[i] <= a; ++i){
            while(a%prime[i]==0){
                num++;
                a/=prime[i];
            }
        }
        if (a!=1)num++;
        for (int i = 0; prime[i] * prime[i] <= b; ++i){
            while(b%prime[i]==0){
                num++;
                b/=prime[i];
            }
        }
        if (b!=1)num++;
        if (k < 2){
            if ((temp1 % temp2 == 0 ||temp2 % temp1 == 0) && temp1 != temp2){
                puts("YES");
            }else puts("NO");
        }else if (k > num){
            puts("NO");
        }else puts("YES");
    }

    return 0;
}

Problem - E - Codeforces

题目大意:模拟题,有两种语句,一种是给定一个变量,对它进行赋值,另一种语句是将两个变量拼接得到第三个变量,求所有变量中包含子串"haha"的个数,每个串只由’h’和’a’组成.
思路:模拟,真的就是模拟,不过直接模拟存不下这么长的字符串,或者你用python写好了交也可以,所以这里需要进行状态压缩,每次拼接只需要保留上次串的前三个和后三个,因为只要拼上一个字符就有可能影响"haha"串的数量,中间的串就可以直接压缩掉,模拟的细节就是需要把几个功能分开写,不然容易出错,(反正我是抄的).

#include<bits/stdc++.h>
using namespace std;

map<string, long long>ans;

long long count(const string& s1, const string& s2){
    long long cnt = 0;
    for (int i = 0; i + s2.size() <= s1.size(); i++){
        if(s1.substr(i, s2.size()) == s2)cnt++;
    }
    return cnt;
}

string getfirst(const string&s){
    if (s.size() <= 3)return s;
    return s.substr(0, 3);
}

string getlast(const string&s){
    if (s.size() <= 3)return s;
    return s.substr(s.size()-3, 3);
}

void solve(){
    ans.clear();
    map<string, string>ma;
    int n;
    cin>>n;
    long long temp = 0;
    while(n--){
        string a, b, c, d, e;
        cin>>a>>b>>c;
        if (b==":="){
            ans[a] = count(c, "haha");
            ma[a] = c;
        }
        else{
            cin>>d>>e;
            string f = ma[c] + ma[e];
            ans[a] = ans[c] + ans[e] + count(getlast(ma[c])+getfirst(ma[e]), "haha");
            if (f.size() > 6){
                f=getfirst(f)+"@"+getlast(f);
            }
            ma[a]=f;
        }
        temp = ans[a];
    }
    cout <<temp <<endl;
}

int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

Problem - F - Codeforces

题目大意:给定a和b,求从a增加到b,有多少个字符发生了改变,例如19就改变了8次,910就改变了2次.
思路:其实有点像找规律,从9到10一定是有额外一次,9x到1xx也是有额外一次,也就是说每出现一个10就会额外产生一次,100也是一样,只需要算出a和b分别额外的次数,再一相减就可以得出答案.

#include<bits/stdc++.h>
using namespace std;

long long r, l;
long long MAX = 1000000000;
long long ans;
int t;
int main(){
    cin>>t;
    while(t--){
        cin>>l >> r;
        ans = 0;
        ans += r-l;
        long long temp = MAX;
        while(temp > 9){
            ans += r/temp;
            temp /= 10;
        }
        temp = MAX;
        while(temp > 9){
            ans -= l/temp;
            temp /= 10;
        }
        cout <<ans <<endl;
    }

    return 0;
}

Problem - G - Codeforces

题目大意:给你四个数a和b,还有c和d, 求a和b最多能分成多少组c和d,每次选择数字组成c和d时只能选择a或者选择b,不能混合选.
思路:二分答案+贪心,二分答案还比较好想,因为主要是个解方程的问题,但是具体怎么判断是向左还是向右取边界,就是贪心的思想了,首先,如果cd中较小的那个数满足当前二分出的答案的话,那么就先将a和b都替换成每组c个元素,然后再将若干个c组合并成d组,此时替换过程中求出的就是已满足c的情况下d尽可能大的个数,如果d的个数满足当前二分答案的话直接右移即可.

#include<bits/stdc++.h>
using namespace std;

int t;
long long a, b, c, d;


int main(){
    cin>>t;
    while(t--){
        cin>>a>>b>>c>>d;
        if (c > d)swap(c, d);
        long long l = 0, r = 2000000001;
        while(r - l >1){
            long long mid = (l+r)>>1;
            bool f = 1;
            if (a < mid*c || b < mid*c)f=0;
            else{
                long long a2 = a-mid*c;
                long long b2 = b-mid*c;
                if (c == d)f = 1;
                else{
                    long long num = a2 / (d - c) + b2 / (d - c);	//将c组进行合并
                    if (num >= mid)f = 1;
                    else f = 0;
                }
            }
            if (f)l = mid;
            else r = mid;
        }
        cout << l <<endl;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值