Educational Codeforces Round 81 (Rated for Div. 2)

A. Display The Number

题目链接:

http://codeforces.com/contest/1295/problem/A

题意:

  一个显示屏,你可以显示很多数字通过亮起一堆段段闪瞎别人的dog眼,比如亮起一个数字1,需要亮起两段,亮起一个数字2,需要亮起5段(如题目图)

  你最多可以亮起n段,问你可以显示最大的数字是多少。

分析:

  用book[i]表示亮起数字i所需的段数,有: book[10]={6,2,5,5,4,5,6,3,7,6};

  发现数字1需要的段最少,要让数字最大,首先他的位数要尽可能多,于是我们把尽量多的段去显示更多的1。

  这时候如果n是偶数,就显示了 n/2 个1 ; 如果n是奇数,可以显示 n/2 个1 ,同时还剩下一个段,这时候可以把开头的1改成 7 ,book[ 1 ] = 2 ,book[ 7 ] = 3 , n就刚好用完。

  这样就可以保证数字是最大的。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
#define ll long long
#define ios std::ios::sync_with_stdio(false)
const ll INF(0x3f3f3f3f3f3f3f3fll);
const int inf(0x3f3f3f3f);
ll book[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int main()
{
    ios;

    ll t;
    cin >> t;
    while (t--)
    {
        ll n; ///不超过n位的
        cin >> n;
        if (n % 2 == 0)
        {
            for (int i = 0; i < n / 2; i++)
            {
                cout << 1;
            }
        }
        else
        {
            cout << 7;
            for (int i = 0; i < n / 2 - 1; i++)
            {
                cout << 1;
            }
        }
        cout << '\n';
    }
    return 0;
}
View Code

 

B. Infinite Prefixes

题目链接:

https://codeforces.com/contest/1295/problem/B

题意:

  给你字符串长度n和x,然后给你长度为n的字符串s,s只包含0和1,字符串t是s的长度无限的重复串,比如s=01001,t是01001 01001.... 

  然后问你 t 的某个前缀中 (0的数量 - 1的数量 ==x) 问这样的前缀有多少个。

分析:

  满足条件的t的前缀,一定是由

  ①若干个的整个儿的字符串s(也可不包含)

  ②长度为 0~n的s的前缀 

  这两部分组成的,所以只要计算:

  ①字符串s中 cnt=0的数量 - 1的数量

  ②字符串s的前缀中 cnt_i[i]=前i个字符中,0的数量 - 1的数量

  判断条件是 (x-cnt_i[i])%cnt == 0  即由若干个s和s的前i个字符组成的字符串满足条件 ans++;

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
#define ll long long
#define ios std::ios::sync_with_stdio(false)
const ll INF(0x3f3f3f3f3f3f3f3fll);
const int inf(0x3f3f3f3f);
int main()
{
    ios;
    ll t;
    cin >> t;
    while (t--)
    {
        ll n, x;
        cin >> n >> x;
        string a;
        cin >> a;
        ll cnt_i[maxn];
        ll cnt0 = 0, cnt1 = 0;
        for (ll i = 0; i < a.size(); i++)
        { ///计算前缀中cnt(0)-cnt(1),保存在cnt_i[i]中
            if (a[i] == '0')
                cnt0++;
            else
                cnt1++;

            cnt_i[i] = cnt0 - cnt1;
        }

        ll cnt = cnt0 - cnt1; ///整个字符串s的cnt(0)-cnt(1)
        if (cnt == 0)
        { ///如果1和0的数量相当
            if (x == 0)
            {
                cout << -1 << endl;
                continue;
            }
            else
            {
                int c = 0;
                for (int i = 0; i < a.size(); i++)
                {
                    if (cnt_i[i] == x)
                    { ///cnt*任意个+cnt_i[i]==x ,由于cnt==0,忽略
                        c++;
                    }
                }
                if (c == 0)
                {
                    cout << 0 << endl;
                    continue;
                }
                else
                { ///如果存在cnt_i[i]==x  又cnt=0,无数个
                    cout << -1 << endl;
                    continue;
                }
            }
        }
        else
        {
            int c = 0;
            if (x == 0)
                c++; ///空前缀的情况
            for (int i = 0; i < a.size(); i++)
                if (((x - cnt_i[i]) % cnt == 0) && (x - cnt_i[i]) / cnt >= 0)
                    c++; ///(x-cnt_i[i])/cnt>=0,因为cnt(0)-cnt(1)有正有负,所以要判断一下
            cout << c << endl;
        }
    }
    return 0;
}
View Code

 

 

C. Obtain The String

题目链接:

 

https://codeforces.com/contest/1295/problem/C

题意:

  给你两个字符串s和t,有一个空串z,你可以疯狂的把s的任何子序列加到字符串z后面,使得z==t,问你最小操作次数。

分析:

  就是问你怎么用s的子序列瞎鸡儿最有顺序的构造z。

  首先,如果t中有一个字符,不存在于s中,当然不能构造啦,所以输出-1。

  然后呢,我们遍历字符串z,当遍历到z[i]的时候,我们找s串里有没有z[i](肯定有啦,没有的都-1了),他的位置在哪里呢?设z[i]在s中的位置在pos(z[i])(说不定有很多个啦,先定义有一个好了)

  ①pos(z[i])>pos(z[i-1])  okk,z[i]选定完成啦!

  ②pos(z[i])<pos(z[i-1])  omg,选不了了,我上个字母选的位置 在 我现在想选的位置的后面啊 ,怎么办呢,结束当前子序列的添加,开始选下一个子序列,而下一个子序列的头 就是我现在想选的位置啦。

  因为字符串都只包含小写字母,所以我们用vector[26]记录'a'~'z'每个字母,都存在s中的哪些位置。

  然后用一个pre 记录,我上一次选的位置,now 记录,我这次想选的位置,如果now>pre,选定成功,反正,结束当前子序列,开始加下一个子序列。

  因为每个字母会存在很多位置,所以用二分查找是否有大于pre的。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
#define ll long long
#define ios std::ios::sync_with_stdio(false)
const ll INF(0x3f3f3f3f3f3f3f3fll);
const int inf(0x3f3f3f3f);
int main()
{
    ios;
    ll t;
    cin >> t;
    while (t--)
    {
        int ans = 0;
        string t, s;
        cin >> s >> t;
        vector<int> pos[26];
        for (int i = 0; i < s.size(); i++)
        { ///记位置
            pos[s[i] - 'a'].push_back(i);
        }

        bool ok = true;
        int pre = -1;
        for (int i = 0; i < t.size(); i++)
        {
            int temp = t[i] - 'a';
            if (pos[temp].empty())
            { ///如果没这个字母
                ok = false;
                break;
            }
            int now = lower_bound(pos[temp].begin(), pos[temp].end(), pre) - pos[temp].begin();
            if (now == pos[temp].size()) ///没找到比pre大的
            {
                ans++;                    ///重新开始
                pre = pos[temp][0] + 1; ///+1是为了避免连续字母找重复
            }
            else
            {
                pre = pos[temp][now] + 1;
            }
        }
        if (!ok)
        {
            cout << -1 << '\n';
        }
        else
        {
            cout << ans + 1 << '\n'; ///+1是因为最后的子序列的最后一个字符不会满足now==pos[temp].size()即ans少+1嘞
        }
    }
    return 0;
}
View Code

 

D. Same GCDs

题目链接:

https://codeforces.com/contest/1295/problem/D

题意:

  给你a和b,让你计算有多少个x(0<=x<m)使得gcd(a,b)=gcd(a+x,b)

分析:

  说实话这题咋一看完全没思路啊,后来被my candy,一个憨憨一个大佬提点才会做QAQ

  是这样的首先,假设有两个数a,b,且gcd(a,b)=1,即a,b互质 , 那我要让gcd(a,b)=gcd(a+x,b)=1,只要找出有多少个数和b互质(数的范围在[0,b))对8?

  没错, 找出和b互质的数有多少个 差不多这样就行了

  可是gcd(a,b)不一定等于1呀 ?

  但是gcd(a/gcd(a,b),b/gcd(a,b)) 一定等于 1 啊

  于是乎,就变成了 找出有多少和 b/gcd(a,b) 互质的数(数的范围在[0,b/gcd(a,b))),而且这个数就是答案啦

  就变成了求欧拉函数的问题了。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
#define ll long long
#define ios std::ios::sync_with_stdio(false)
const ll INF(0x3f3f3f3f3f3f3f3fll);
const int inf(0x3f3f3f3f);
long long gcd(long long b, long long c) //计算最大公约数
{
    return c == 0 ? b : gcd(c, b % c);
}
int main()
{
    ios;
    ll t;
    cin >> t;
    while (t--)
    {
        ll a, m;
        cin >> a >> m;
        ll res = gcd(a, m);
        a /= res, m /= res;
        ll ans = m;
        for (ll i = 2; i * i <= m; i++)
        {
            if (m % i == 0)
            {
                ans -= ans / i;
                while (m % i == 0)
                    m /= i;
            }
        }
        if (m > 1)
            ans -= ans / m;
        cout << ans << endl;
    }
    return 0;
}
View Code

 

看了别人的代码发现自己真是个大蒟蒻,所以:

代码和E题看这里->https://www.cnblogs.com/StarRoadTang/p/12249128.html

posted @ 2020-02-01 21:58  GoodVv  阅读(238)  评论(0编辑  收藏  举报