Codeforces Round #267 (Div. 2) solution

A.George and Accommodation

题目大意:给你n个宿舍的可以容纳的人数和现在已住的人数,问有几个宿舍可以安排两个人进去住。

解法:模拟,无trick。

代码:

 1 #include <cstdio>
 2
 3 int main() {
 4     int n;
 5     while(scanf("%d", &n) != EOF){
 6         int a, b, ans = 0;
 7         for(int i = 0; i < n; i++) {
 8             scanf("%d%d", &a, &b);
 9             if(b - a >= 2) ans++;
10         }
11         printf("%d\n", ans);
12     }
13
14     return 0;
15 }

B.Fedor and New Game

题目大意:给你m+1个数,问前m个数的二进制和最后一个数不同的位数小于等于k个的数的个数。

解法:模拟,无trick。求不同的位数可先异或然后看有多少个1。

代码:

 1 #include <cstdio>
 2
 3 int a[1010];
 4
 5 int main() {
 6     int n, m, k;
 7     while(scanf("%d%d%d", &n, &m, &k) != EOF){
 8         int ans = 0;
 9         for(int i = 0; i < m; i++) scanf("%d", &a[i]);
10         scanf("%d", &a[m]);
11         for(int i = 0; i < m; i++) {
12                 int p = a[i] ^ a[m], t = 0;
13                 while(p > 0) {
14                     if(p % 2 == 1) t++;
15                     p /= 2;
16                 }
17                 if(t <= k) ans++;
18         }
19         printf("%d\n", ans);
20     }
21
22     return 0;
23 }

C.George and Job

题目大意:从n个数中选出m段不相交的子串,子串的长度均为k,问所有选出来的子串的所有数的和最大为多少。

解法:DP即可。dp[i][j]表示从前i个数选出j段的最大和,转移很明显。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int a[5010];
long long s[5010], dp[5010][5010];

int main() {
    int n, m, k;
    while(scanf("%d%d%d", &n, &m, &k) != EOF){
        int ans = 0;
        s[0] = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            s[i] = s[i - 1] + a[i];
        }
        for(int i = m; i <= n; i++) {
            for(int j = k; j >= 1; j--)  dp[i][j] = max(dp[i - 1][j], dp[i - m][j - 1] + s[i] - s[i - m]);
        }
        printf("%I64d\n", dp[n][k]);
    }

    return 0;
}

D.Fedor and Essay

题目大意:给你一篇由一些单词构成的文章,单词不区分大小写。再给你一些单词的转化关系,即单词a可以被单词b替换(注意是单向的,sb出题人写input里面算什么!)。你可以无限的进行替换操作,现在希望被替换后的文章r的数量最少,在此基础上总长度最短。

解法:显然如果是一个DAG的话我们就可以直接对每个点进行记忆化搜索来更新答案,对这道题显然可以进行缩点,新的点的属性由这个强联通分量里面r最小的情况下最短的单词决定。但是对于这道题的情况我们可以不缩点,按照点的大小关系(即先看r的数量最少的,r一样的情况下看最短的)进行dfs也是正确的(当然直接记忆化搜索是错的,在环的更新上会出现问题)。

代码:

#include <cstdio>
#include <map>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

const int N = 100010;

struct Node {
    int r, l, p;
}g[5 * N];

int ar[5 * N], al[5 * N], u[5 * N];

map<string, int> mp;
char s[5 * N], t[5 * N];
vector<int> e[5 * N], lis;

int calc(char q[]) {
    int res = 0;
    for(int i = 0; q[i] != ‘\0‘; i++) {
        if(q[i] >=‘A‘ && q[i] <= ‘Z‘) q[i] = q[i] - ‘A‘ + ‘a‘;
        if(q[i] == ‘r‘) res++;
    }
    return res;
}

bool cmp(const Node &a, const Node &b) {
    if(a.r != b.r) return a.r < b.r;
    if(a.l != b.l) return a.l < b.l;
    return a.p < b.p;
}

void dfs(int x, int r, int l) {
    if(u[x]) return;
    u[x] = 1;
    if(r == ar[x]) al[x] = min(al[x], l);
    if(r < ar[x]) {
        ar[x] = r, al[x] = l;
    }
    for(int i = 0; i < e[x].size(); i++) {
        int y = e[x][i];
        dfs(y, r, l);
    }
}

int main() {
    int n, m;
    while( scanf("%d", &m) != EOF ) {
        int n = 0;
        for(int i = 0; i < m; i++) {
            scanf("%s", s);
            int temp = calc(s);
            if(mp[s] == 0) {
                mp[s] = ++n;
                g[n].r = temp;
                g[n].l = strlen(s);
                g[n].p = n;
            }
            lis.push_back(mp[s]);
        }
        int k = m;
        scanf("%d", &m);
        for(int i = 0; i < m; i++) {
            scanf("%s", s);
            int temp = calc(s);
            if(mp[s] == 0) {
                mp[s] = ++n;
                g[n].r = temp;
                g[n].l = strlen(s);
                g[n].p = n;
            }
            scanf("%s", t);
            temp = calc(t);
            if(mp[t] == 0) {
                mp[t] = ++n;
                g[n].r = temp;
                g[n].l = strlen(t);
                g[n].p = n;
            }
            e[mp[t]].push_back(mp[s]);
        }
        sort(g + 1, g + n + 1, cmp);
        for(int i = 1; i <= n; i++) {
            ar[g[i].p] = g[i].r;
            al[g[i].p] = g[i].l;
        }
        for(int i = 1; i <= n; i++) dfs(g[i].p, g[i].r, g[i].l);
        long long ov = 0, ol = 0;
        for(int i = 1; i <= k; i++) ov += ar[lis[i - 1]], ol += al[lis[i - 1]];
        printf("%I64d %I64d\n", ov, ol);
    }

    return 0;
}

E.Alex and Complicated Task

题目大意:给你n个数,你需要找到一个最长的子序列,使得这个子序列的第4k-4k+3项为a,b,a,b的形式(从0标号)。

解法:我们把数组记为a[]。我们考虑每一对儿相等的数。首先如果某个数出现了4次,那么这4个数可以构成一个答案。假设我以(l, r)表示一对儿相同的数,即a[l] = a[r]。我们按r从小到大对所有的相同数对进行排序。我们考虑开始的两个数对,假设一个为(a, b),另一个为(c, d),显然有d > b。如果c <= a,那么明显如果某个数对和(a, b)可以构成答案的话和(c, d)也可以构成答案,也就是说(a, b)是没有用的,我们把(a, b)删掉。如果a<c<=b,那么(a, b)和(c, d)可以构成一个答案。如果c > b的话,那么这是两个不相交的线段,我们同时保留(a, b)和(c, d)。我们照此模拟即可。一些细节和具体的思路可以参考代码。

代码:

#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#include <string>
#include <cstring>
using namespace std;

const int N = 500010;

int a[N];

struct P {
    int l, r, x;
}p[N];

map<int, int> cnt, pos;
vector<int> o;
int np = 0;

void copy(int a, int b) {
    o.push_back(a);
    o.push_back(b);
    o.push_back(a);
    o.push_back(b);
    cnt.clear();
    pos.clear();
    np = 0;
}

int main() {
    int n;
    while( scanf("%d", &n) != EOF ) {
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++) {
            int x = a[i];
            if(cnt[x] != 0) cnt[x]++;
            else cnt[x] = 1;
            if(cnt[x] == 4) { copy(x, x); continue;}
            if(pos[x] == 0) { pos[x] = i; continue; }
            int l = pos[x], r = i;
            pos[x] = i;
            while(np > 0) {
                int nl = p[np - 1].l, nr = p[np - 1].r, nx = p[np - 1].x;
                if(nl < l && l < nr) { copy(nx, x); break; }
                else if(l <= nl) np--;
                else {
                    p[np].l = l, p[np].r = r, p[np++].x = x;
                    break;
                }
            }
            if(np == 0) p[np].l = l, p[np].r = r, p[np++].x = x;
        }
        printf("%d\n", (int)o.size());
        for(int i = 0; i < (int)o.size(); i++) printf("%d%c", o[i], i == (int)o.size() - 1?‘\n‘:‘ ‘);
    }

    return 0;
}

时间: 2024-12-09 09:33:08

Codeforces Round #267 (Div. 2) solution的相关文章

Codeforces Round #267 (Div. 2) C. George and Job(DP)补题

Codeforces Round #267 (Div. 2) C. George and Job题目链接请点击~ The new ITone 6 has been released recently and George got really keen to buy it. Unfortunately, he didn't have enough money, so George was going to work as a programmer. Now he faced the follow

01背包 Codeforces Round #267 (Div. 2) C. George and Job

题目传送门 1 /* 2 题意:选择k个m长的区间,使得总和最大 3 01背包:dp[i][j] 表示在i的位置选或不选[i-m+1, i]这个区间,当它是第j个区间. 4 01背包思想,状态转移方程:dp[i][j] = max (dp[i-1][j], dp[i-m][j-1] + sum[i] - sum[i-m]); 5 在两个for循环,每一次dp[i][j]的值都要更新 6 */ 7 #include <cstdio> 8 #include <cstring> 9 #i

Codeforces Round #275 (Div.1) Solution

好久没做题了,开场Virtual热热身. A 构造,我的方法是,取1,2,3...,k这几个差值,前k+1个数分别是 1, k+1, 2, k, ...., 之后就k+2, k+3, ..., n B 因为题设是与操作.我们按照每一位来,如果有一个限制某位是1,则将那段区间标志1,没有限制的位全部置零即可,然后检验为0的位是否全是1.标志一段区间可以用标记法,检验可以求和看差值. C 我做完之后看了CF tutorial 跟我的做法不同.我的做法比他给的复杂度低一点,不过题解好帅,而且跑出来速度

Codeforces Round #282 (Div.1) Solution

上午考试,下去去参观教堂,回来睡大觉,搞到现在才有时间做,水平恢复中. A 倒过来扫括号匹配很容易理解 B dp[i]表示最后一个拿到i的数目,sum[i]表示前i项dp和,sum2[i]表示前i项sum和.显然.dp[i]=sum2[o], o是最右边的坐标使得s[o+1,i]能包含t. C Interesting,我建了个树,硬着dp搞得..还没优化就46ms,想来这种题数据也不好构造. D Editorial似乎说离线搞,不过我在线搞出来了.我存了每个节点子树平方和,子树和,整体和,整体平

[比赛] Codeforces Round #538 (Div. 2) solution (贪心,数学其他,二分,线段树)

已经写了100篇题解啦! link solution pdf #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read(){ int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c

Codeforces Round #607 (Div. 1) Solution

从这里开始 比赛目录 我又不太会 div 1 A? 我菜爆了... Problem A Cut and Paste 暴力模拟一下. Code #include <bits/stdc++.h> using namespace std; typedef bool boolean; const int N = 1e6 + 5; const int Mod = 1e9 + 7; int T; int x; int len; char s[N]; int paste(int s1, int t1, in

Codeforces Round #267 (Div. 2) C. George and Job

The new ITone 6 has been released recently and George got really keen to buy it. Unfortunately, he didn't have enough money, so George was going to work as a programmer. Now he faced the following problem at the work. Given a sequence of n integers p

Codeforces Round #267 (Div. 2)

A.George and Accommodation 题意:给定数组a,b,问b-a>=2有多少个 思路:直接模拟.. B.Fedor and New Game 题意:给定m+1个n位以内的二进制数,求前m个有多少个跟第m+1的二进制下不同位数不超过k的个数 思路:直接模拟 C.George and Job 题意:给定n个数,求k个的段,每段有m个连续得数,使得和最大 思路:直接dp,注意long long不会超内存 1 /* 2 * Author: Yzcstc 3 * Created Tim

Codeforces Round #268 (Div. 1) solution

A.24 Game 题意:给你1, 2, ..., n-1, n 这个序列,每次你可以取出两个数做+/-/*三种操作之一,然后把结果放回到序列中,询问能否是的这个序列最后只剩下一个24. 解法:首先很明显n < 4的时候是无解的.如果n=4,那么1 * 2 * 3 * 4=24,如果n=5,那么(5 - 1 - 2) * 3 * 4 = 24.若n > 5,那么我可以做n - (n - 1) = 1,相当于变成了n-2时候的情况加一个1,那么显然最后让答案乘上这个1即可. 代码: includ