Edu Codeforces 103 (div2)

第一次 div2四道题!(可能是教育场简单一点),cf打多了就会有感觉了,真的思维题偏多,就看谁想的快敲的快,前面几题用到的算法知识几乎没有,多打可以锻炼思维。比赛的时候犯了几个傻 * 错误,导致多了几个罚时,挺不应该的,但是这次的题真的不难,包括补的E题(剩下两题一题没人做出来,一题就个位数的人,我就不奢望补了)

题目链接

A. K-divisible Sum

题意

给你n, k,让你找n个数,这n个数的和可以被k整除,求这n个数中最大值的最小值。

分析

嗯,求最大值的最小值,那不就是二分答案吗?然后开始构思check函数……什么玩意,这咋check,然后开始从其他角度分析,设这n个数和为sum,要求最大值的最小值,先求一个大于等于sum且能被n整除的值x,然后x/n就是最大值的最小值。接下来去找sum,自然而然,sum肯定要尽量小,那么就找大于等于n的k的最小倍数即可。

比赛的时候犯了个弱智的错误,找上面的x值我直接用 while(x%n) x++; 然后就T掉了…其实除一下就可以O(1)内算出来的。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+10;
const double PI = acos(-1.0);
typedef pair<int,int> PII;

int main(int argc, char const *argv[]) {
    LL n, k, t;
    cin >> t;
    while(t--) {
        cin >> n >> k;
        LL sum;
        if(n%k != 0)
            sum = (n/k+1)*k;
        else sum = n;
        LL temp = sum;
        if(sum%n != 0)
        temp = (sum/n+1)*n;
        cout << temp/n << endl;
    }
    return 0;
}

B. Inflation

题意

给你n个数p和k,你可以随意地给 $p_i$ 加上一定的值,要求使得对于任意的 $p_i$ ,满足 $ \frac {p_i}{\sum\limits_{j=0}^{i-1} w_j} \le \frac k {100}(0 < i < n)$,求加上的值的总和最小值。

分析

由于只能把值改大不能改小,所以如果第 i 个位置不符合要求,只能改0到i-1这一段的p值,如果修改 $p_k$ 那么它对 $p_k$ 到 $p_n$ 都有贡献,所以为了每次修改后贡献最大,我们可以从后往前遍历,如果有一个位置不满足要求,则增大 $p_0$, 因为$p_0$ 可以使得其后面所有位置都更优。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5 + 10;
const double PI = acos(-1.0);
typedef pair<int, int> PII;
LL p[maxn], s[maxn];
int main(int argc, char const *argv[]) {
    LL n, k, t;
    cin >> t;
    while (t--) {
        cin >> n >> k;
        for (int i = 1; i <= n; i++)
            scanf("%lld", &p[i]), s[i] = s[i - 1] + p[i];
        LL ans = 0;
        for (int i = n; i >= 2; i--) {
            if (p[i] * 100 > k * (s[i - 1] + ans)) {
                ans += (ceil(100*p[i]*1.0/k) - (s[i-1]+ans));
            }
        }
        cout << ans << endl;
    }
    return 0;
}

C. Longest Simple Cycle

题意

按照题目要求得到一张图,找到最大的一个环。

题目分析

直接从左往右来就行,维护一个当前环的大小以及最大值,如果下一个位置封死了,不能和当前环链接,就新建一个环。主要有四个坑:
1. a并不一定小于b(这点样例有),所以要用abs。
2. 第一个环的计算是 $c[i] + 1 + abs(a[i]-b[i])$。
3.下一个环链接已有的环时有两条路可以走,可以向外走和已有的环组成一个大环,也可以直接往内走,自成一个新环,要取max,这里比赛时没考虑到,导致wa3。
4. 可能超int,这里我比赛时考虑到了,但是有个地方还是漏写了long long,导致wa5。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5 + 10;
const double PI = acos(-1.0);
typedef pair<int, int> PII;
LL a[maxn], b[maxn], c[maxn];
int main(int argc, char const *argv[]) {
    LL n,  t;
    cin >> t;
    while (t--) {
        cin >> n;
        for(int i = 0; i < n; i++) scanf("%lld", &c[i]);
        for(int i = 0; i < n; i++) scanf("%lld", &a[i]);
        for(int i = 0; i < n; i++) scanf("%lld", &b[i]);
        LL ans = -1, now = 0;
        for(int i = 1; i < n; i++) {
            if(a[i] == b[i]) {
                now = c[i] + 1;
            }
            else {
                if(now == 0) now = c[i] + 1 + abs(a[i]-b[i]);
                else {
                    now = c[i] + 1 + max(now - abs(a[i] - b[i]),abs(a[i]-b[i]));
                }
            }
            ans = max(ans, now);
        }
        cout << ans << endl;
    }
    return 0;
}

D. Journey

题意

一共有n+1座城市,编号0-n,每相邻两座城市之间有一条有向边,共n条边,给你一个仅由’L’和’R’组成的长n的字符串表示n条边的初始方向,一个游客从一座城市出发,每天必须沿着有向边向相邻的一座城市走,并且每天有向边都会变换一次方向(朝左变成朝右,朝右变成朝左),若游客不能向左也不能向右走,则结束旅行。输出从每座城市开始,可以访问的最多城市数。

分析

首先,如果一个人可以到达某个城市,那么他还可以原路返回,并且到起点时,所有路的方向和初始相同。那么我们只要考虑每座城市向左最远可以到哪里,向右可以到哪里,加起来即可。观察可知,只有形似LRLRLR的才能畅通无阻,所有我们分别从左向右和从右向左遍历一次字符串,记录以每个位置开始向左有几个“LRLRL”以及向右有几个“LRLRL”,然后遍历一下每座城市,判断初始时是否可以向左走,如果可以,则最远距离就是向左的“LRLRLR”的长度,向右同理,左右城市数相加再+1(起点城市)就是答案。

我觉得这题的主要难点就是下标的对应关系,可以举个例子看一下下标之间的关系。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 3e5 + 10;
const double PI = acos(-1.0);
typedef pair<int, int> PII;
char s[maxn];
int zuo[maxn], you[maxn];
int main(int argc, char const *argv[]) {
    LL n,  t;
    cin >> t;
    while (t--) {
        cin >> n;
        cin >> s;
        zuo[0] = 0, zuo[1] = 1;
        for(int i = 1; i < n; i++) {
            if(s[i] != s[i-1]) {
                zuo[i+1] = zuo[i] + 1;
            }
            else zuo[i+1] = 1;
        }
        you[n] = 0, you[n-1] = 1;
        for(int i = n-1; i >= 1; i--){
            if(s[i] == s[i-1]) {
                you[i-1] = 1;
            }
            else {
                you[i-1] = you[i] + 1;
            }
        }
        for(int i = 0; i <= n; i++) {
            if(i == 0) {
                if(s[i] == 'R') cout << you[i] + 1 << ' ';
                else cout << 1 << ' ';
            }
            else if(i == n) {
                if(s[i-1] == 'L') cout << zuo[i] + 1<< " ";
                else cout << 1 << endl;
            }
            else {
                int ans = 0;
                if(s[i] == 'R') ans += you[i];
                if(s[i-1] == 'L') ans += zuo[i];
                cout << ans+1 << " ";
            }
        }
        puts("");
    }
    return 0;
}

E. Pattern Matching(拓扑)

题意

给你n个模式串,编号1-n,模式串中可能含有‘ _ ’,表示这个位置可以放任何值。再给你m个匹配串,每个匹配串后带一个值 $m_i$ ,模式串和匹配串的大小都为k。让你找到任意一个模式串的下标的序列,满足第 i 个匹配串对应的所有模式串,在序列中第一个出现的下标为 $m_i$。

分析

每个匹配串可能对应多个模式串,对于某个匹配串,要求第mi个模式串在序列中是最先出现的,我们将所有的模式串看成一个点,对于每个匹配串,将mi和所有该匹配串可以对应的模式串对应的点连边,只要找到拓扑序,就是一种满足题目要求的解。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 3e5 + 10;
const double PI = acos(-1.0);
typedef pair<int, int> PII;

unordered_map<string, int> ha;
string p[maxn];
vector<int> mp[maxn];
int in[maxn];
int n, m, k;
bool judge(string &s, string &p) {
    for(int i = 0; i < k; i++) {
        if(s[i] != p[i] && p[i] != '_') return false;
    }
    return true;
}

int main(int argc, char const *argv[]) {  
    cin >> n >> m >> k;
    for(int i = 1; i <= n; i++) {
        cin >> p[i];
        ha[p[i]] = i;
    }
    for(int i = 0; i < m; i++) {
        int mt;
        string s;
        cin >> s >> mt;
        if(!judge(s, p[mt])) {
            puts("NO");
            return 0;
        }
        for(int i = 0; i < 1 << k; i++) {
            string temp = s;
            for(int j = 0; j < k; j++) {
                if(i >> j & 1) temp[j] = '_';
            }
            if(ha.find(temp) == ha.end() || ha[temp] == mt) continue;
            mp[mt].push_back(ha[temp]);
            in[ha[temp]]++;
        }
    }
    queue<int> q;
    vector<int> ans;
    for (int i = 1; i <= n; i++) {
        if (in[i] == 0) {
            q.push(i);
        }
    }
    while (q.size()) {
        int now = q.front();
        q.pop();
        ans.push_back(now);
        for (int i = 0; i < mp[now].size(); i++) {
            in[mp[now][i]]--;
            if (in[mp[now][i]] == 0) 
                q.push(mp[now][i]);
        }
    }
    if(ans.size() != n) puts("NO");
    else {
        puts("YES");
        for(int i = 0; i < n; i++) cout << ans[i] << ' ';
    }
    return 0;
}
暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇