Educational Codeforces Round 72 (Rated for Div. 2)

A. Creating a Character

这个题目卡了我挺久的,这个有一个条件没有考虑到,就是这个最大只有exp+1

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int mx = 1e6 + 10;
const int maxn = 1e5 + 10;

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        ll a, b, c;
        cin >> a >> b >> c;
        ll sum = a + b + c;
        sum = (sum - 1) >> 1ll;
        ll ans = sum - b + 1;
        ans = max(0*1ll, ans);
        cout << min(ans, c + 1) << endl;
    }
    return 0;
}
A

 

B. Zmei Gorynich

这个题目和之前的A差不多,有些临界条件要考虑

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int mx = 1e6 + 10;
const int maxn = 1e5 + 10;


int main()
{
    int t;
    scanf("%d", &t);
    while (t--) {
        ll n, x, maxs = 0, ans = 0;
        scanf("%lld%lld", &n, &x);
        for (int i = 1; i <= n; i++) {
            ll d, h;
            scanf("%lld%lld", &d, &h);
            maxs = max(maxs, d);
            ans = max(ans, d - h);
        }
        if (maxs >= x) {
            printf("1\n");
            continue;
        }
        if (ans == 0) {
            if (maxs < x) printf("-1\n");
            continue;
        }
        ll num = (x - maxs + ans - 1) / ans + 1;
        printf("%lld\n", num);
    }
    return 0;
}
B

 

C. The Number Of Good Substrings

这个题目就是求一下每一个1和这个1前面0的个数。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
char s[maxn];
ll vis[maxn], pos[maxn];
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%s", s);
        ll len = strlen(s), cnt = 0, tot = 0;
        memset(vis, 0, sizeof(vis));
        for(int i=0;i<len;i++)
        {
            if (s[i] == '0') cnt++;
            else {
                vis[++tot] = cnt;
                pos[tot] = i;
                cnt = 0;
            }
        }
        ll ans = 0;
        for(int i=1;i<=tot;i++)
        {
            ll res = 0, num = 0;
            for (int j = pos[i]; j < len; j++) {
                res = res * 2 + s[j] - '0';
                num++;
                if (res - num <= vis[i]) ans++;
                else break;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}
 
C

 

D. Coloring Edges

题目大意是:

给你一个有向图,然后问这个图每一个循环都至少有两种颜色,最少要用多少种颜色。

这个是给边染色,因为没有重边和自循环,

每一个环的构成是肯定有从数值小的顶点到数值比较大的顶点,所以我们对于每一个边的染色。

只要把从数值小的指向数值大的都染成1,数值大的指向数值小的染成2就可以了。

这个一个环里面肯定至少有两种颜色,因为每一条边都是只会被染一次,所以肯定没有矛盾。

但是把染边改成染点,这个该怎么写呢?不太会。。。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
vector<int>G[maxn];
int d[maxn], n, m;
void add(int u, int v) {
    G[u].push_back(v);
    d[v]++;
}
struct node
{
    int u, v;
    node(int u=0,int v=0):u(u),v(v){}
}ex[maxn];

bool tp() {
    int cnt = 0;
    queue<int>que;
    for (int i = 1; i <= n; i++) {
        if (d[i] == 0) que.push(i);
    }
    while (!que.empty()) {
        int u = que.front(); que.pop(); cnt++;
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            d[v]--;
            if (d[v] == 0) que.push(v);
        }
    }
    if (cnt == n) return 0;
    return 1;
}

int main() {
    memset(d, 0, sizeof(d));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
        ex[i] = node(u, v);
    }
    int f = tp();
    if (f) {
        printf("2\n");
        for (int i = 1; i <= m; i++) {
            if (ex[i].u < ex[i].v) printf("1 ");
            else printf("2 ");
        }
        printf("\n");
    }
    else {
        printf("1\n");
        for (int i = 1; i <= m; i++) printf("1 ");
        printf("\n");
    }
    return 0;
}
D

 

E. Sum Queries?

这个是一个比较简单的线段树,思路出的很快,但是写的有点搓。

我一开始建了两棵线段树,后来发现可以只建一颗,建两棵线段树的复杂度有点高,加了快读和快输卡着时间过去的。

然后删了一颗线段树之后,大概也要1000多ms,可能是我的这个写法时间复杂度偏高,我是记录了最小和次小值,然后query求一个区间的最小和次小值。

lj是直接用数组记录了一个区间的最小和次小值之和,然后再记录一个区间的最小值,这个是方便区间合并的时候用。

这个时间复杂度就比较低大概是500ms左右。

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int mins[10][maxn * 4], nmins[10][maxn * 4];
int n, m;
inline int read() {
    int X = 0; bool flag = 1; char ch = getchar();
    while (ch<'0' || ch>'9') { if (ch == '-') flag = 0; ch = getchar(); }
    while (ch >= '0'&&ch <= '9') { X = (X << 1) + (X << 3) + ch - '0'; ch = getchar(); }
    if (flag) return X;
    return ~(X - 1);
}
 
inline void write(int X) {
    if (X < 0) { putchar('-'); X = ~(X - 1); }
    int s[20], top = 0;
    while (X) { s[++top] = X % 10; X /= 10; }
    if (!top) s[++top] = 0;
    while (top) putchar(s[top--] + '0');
    putchar('\n');
}
 
void update2(int i, int id, int l, int r, int pos, int val) {
    // printf("i=%d id=%d l=%d r=%d pos=%d val=%lld\n", i, id, l, r, pos, val);
    if (l == r) {
        mins[i][id] = val;
        nmins[i][id] = inf * 2;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) update2(i, id << 1, l, mid, pos, val);
    else update2(i, id << 1 | 1, mid + 1, r, pos, val);
    mins[i][id] = min(mins[i][id << 1], mins[i][id << 1 | 1]);
    nmins[i][id] = min(min(nmins[i][id << 1], nmins[i][id << 1 | 1]), max(mins[i][id << 1], mins[i][id << 1 | 1]));
}
int ans1, ans2;
void  query2(int i, int id, int l, int r, int x, int y) {
    // printf("i=%d id=%d l=%d r=%d x=%d y=%d\n", i, id, l, r, x, y);
    if (x <= l && y >= r) {
        // printf("ans1=%lld ans2=%lld mins[%d][%d]=%lld\n", ans1, ans2, i, id, mins[i][id]);
        if (ans1 > mins[i][id]) {
            ans2 = ans1;
            ans1 = mins[i][id];
        }
        else if (ans2 > mins[i][id]) ans2 = mins[i][id];
        ans2 = min(ans2, nmins[i][id]);
        // printf("ans1=%lld ans2=%lld\n", ans1, ans2);
        return;
    }
    int mid = (l + r) >> 1;
    if (x <= mid) query2(i, id << 1, l, mid, x, y);
    if (y > mid) query2(i, id << 1 | 1, mid + 1, r, x, y);
}
 
 
void build(int i,int id,int l,int r)
{
    mins[i][id] = nmins[i][id] = inf * 2;
    if(l==r) return;
    int mid = (l + r) >> 1;
    build(i, id << 1, l, mid);
    build(i, id << 1 | 1, mid + 1, r);
}
 
int main() {
    n = read(), m = read();
    for (int i = 0; i < 10; i++) build(i, 1, 1, n);
    for (int i = 1; i <= n; i++) {
        int x, w;
        x=read(),w = x;
        for (int j = 0; j < 10; j++) {
            int val = x % 10; x /= 10;
            if(val) update2(j, 1, 1, n, i, w);
            else update2(j, 1, 1, n, i, inf * 2);
        }
    }
    while (m--) {
        int opt, x, y;
        opt = read(), x = read(), y = read();
        if (opt == 1) {
            int w = y;
            for (int i = 0; i < 10; i++) {
                int val = y % 10; y /= 10;
                if (val) update2(i, 1, 1, n, x, w);
                else update2(i, 1, 1, n, x, inf * 2);
            }
        }
        else {
            int ans = inf * 2;
            for (int i = 0; i < 10; i++) {
                ans1 = ans2 = inf * 2;
                query2(i, 1, 1, n, x, y);
                ans = min(ans*1ll, ans1*1ll + ans2);
            }
            if (ans >= inf * 2) write(-1);
            else write(ans);
        }
    }
    return 0;
}
E

 

posted @ 2019-09-07 00:37  EchoZQN  阅读(217)  评论(0编辑  收藏  举报