Educational Codeforces Round 78 (Rated for Div. 2) 题解

  • Shuffle Hashing
  • A and B
  • Berry Jam
  • Segment Tree
  • Tests for problem D
  • Cards

Shuffle Hashing

\[ Time Limit: 2 s\quad Memory Limit: 256 MB \]
处理出 \(s_1\) 中各个字符出现的次数,然后双指针维护 \(s_2\) 中每一段长度为 \(len(s_1)\) 的串中字符出现的次数,如果存在某一段和 \(s_1\) 的字符次数相同,则是答案。


view

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pb         push_back
#define  pii        pair
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e2 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m, k;
int cas, tol, T;

int cnt[26];
char s1[maxn], s2[maxn];

bool ok() {
    for(int i=0; i<26; i++) if(cnt[i])  return 0;
    return 1;
}

int main() {
    scanf("%d", &T);
    while(T--) {
        mes(cnt, 0);
        scanf("%s%s", s1+1, s2+1);
        n = strlen(s1+1), m = strlen(s2+1);
        if(n>m) {
            puts("NO");
            continue;
        }
        for(int i=1; i<=n; i++) cnt[s1[i]-'a']++;
        for(int i=1; i<=n; i++) cnt[s2[i]-'a']--;
        bool f = 0;
        for(int i=n; i<=m; i++) {
            if(ok())    f = 1;
            if(i==m)    break;
            cnt[s2[i+1]-'a']--;
            cnt[s2[i-n+1]-'a']++;
        }
        puts(f ? "YES" : "NO");
    }
    return 0;
}

A and B

\[ Time Limit: 1 s\quad Memory Limit: 256 MB \]
说出来你可能不信,强行 \(oeis\) 过了。


view

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pb         push_back
#define  pii        pair
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

ll n, m;
int cas, tol, T;

int main() {
    scanf("%d", &T);
    while(T--) {
        ll a, b;
        scanf("%lld%lld", &a, &b);
        n = abs(a-b);
        ll k=0;
        for(; ; k++) {
            if(k*(k+1)/2 <= n && n<(k+1)*(k+2)/2)   break;
        }
        ll tk = k*(k+1)/2;
        ll ans;
        if(n == tk) ans = k;
        else {
            if(k%2 == 1) {
                if((n-tk)%2==1) ans = k+2;
                else    ans = k+1;
            } else {
                if((n-tk)%2==1) ans = k+1;
                else    ans = k+3;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

Berry Jam

\[ Time Limit: 2 s\quad Memory Limit: 256 MB \]
预处理后半段中 \(1\)\(2\) 多吃 \(x\) 瓶所需要的最少步数,然后枚举前半段中吃到第 \(i\) 瓶处,\(1\) 还需要比 \(2\) 多吃 \(y\) 瓶,然后在后半段预处理中找答案。


view

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pb         push_back
#define  pii        pair
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 2e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;

int a[maxn];
unordered_map mp;

int main() {
    scanf("%d", &T);
    while(T--) {
        mp.clear();
        scanf("%d", &n);
        int y = 0;
        for(int i=1; i<=n+n; i++) {
            scanf("%d", &a[i]);
            y += a[i]==1 ? 1:-1;
        }
        if(y == 0) {
            printf("0\n");
            continue;
        }
        mp[0] = 0;
        for(int i=n+1, x=0; i<=n+n; i++) {
            x += a[i]==1 ? 1:-1;
            if(!mp.count(x))    mp[x] = i-n;
        }
//      for(auto t : mp)    printf("%d %d\n", t.fi, t.se);
        int ans = inf;
        for(int i=n; i>=0; i--) {
            if(mp.count(y)) 
                ans = min(ans, n-i+mp[y]);
            if(!i)  break;
            y -= a[i]==1 ? 1:-1;
        }
        printf("%d\n", ans);
    }
    return 0;
}

Segment Tree

\[ Time Limit: 2 s\quad Memory Limit: 256 MB \]
把线段先按 \(l\) 在按 \(r\) 排序,然后枚举第 \(i\) 条线段,判断它可以和哪些线段连边。

可以发现,在枚举第 \(i\) 条线段时,前 \(i-1\) 条线段的 \(l\) 一定都是比我的 \(l\) 小的,所以我其实是需要找到前 \(i-1\) 条线段中,找到所有满足 \(p[i].l \leq p[j].r \leq p[i].r\) 的所有 \(j\)

这一段区间是连续的,所以我们可以维护一个 \(set\)\(pair\),用来存放前 \(i-1\) 条边的 \(r\) 位置和编号。然后用 \(set\) 的二分来快速找到所有的 \(j\)

又因为想要形成一棵树,这也就意味着最多只会添加 \(n-1\) 条边,那么整体复杂度就不会太大。


view

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  l          first
#define  r          second
#define  pb         push_back
#define  pii        pair
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)
 
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 5e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;

int fa[maxn];
pii p[maxn];
set st;

int find(int x) {
    return fa[x]==x ? x : fa[x]=find(fa[x]);
}

bool bind(int x, int y) {
    x = find(x), y = find(y);
    if(x == y)  return 0;
    fa[x] = y;
    return 1;
}

int main() {
    scanf("%d", &n);
    for(int i=1; i<=n; i++) {
        scanf("%d%d", &p[i].l, &p[i].r);
        fa[i] = i;
    }
    sort(p+1, p+1+n);
    st.clear();
    int sz = 0, f = 1;
    for(int i=1; i<=n; i++) {
        auto pos = st.lower_bound({p[i].l, -1});
        for(auto j = pos; j!=st.end(); j++) {
            if((*j).l > p[i].r) break;
            sz++;
            if(sz==n || !bind(i, (*j).r)) {
                f = 0;
                break;
            }
        }
        if(!f)  break;
        st.insert({p[i].r, i});
    }
    set ans;
    for(int i=1; i<=n; i++) ans.insert(find(i));
    puts(ans.size()==1&&f ? "YES" : "NO");
    return 0;
}

Tests for problem D

\[ Time Limit: 2 s\quad Memory Limit: 256 MB \]
考虑模拟一下第一个样例,它的放置规则是先把 \(1\) 看成整棵树的根,那么可以先确定 \(p[1].r = 2*n\),然后它有两个直接儿子,所以我需要在 \(r\) 前面留两个空给这两个儿子放 \(r\) 用,现在已经没有直接儿子了,为了防止新的交叉出现,接下来我就放上自己的 \(l\),对于下面的儿子也是同理,可以递归处理。

然后就是儿子的 \(l\) 问题了,由于 \(1\) 的各个儿子不能有交叉部分,也就意味着这些得是重合起来的,所以一开始放在最后的 \(r\),其对应的 \(l\) 就应该尽量小,所以我越早放在后面的儿子,应该越晚去 \(dfs\) 确定其 \(l\)

为了防止数字重复被用到,可以用一个 \(set\) 来维护还可以用的数字。


view

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  l          first
#define  r          second
#define  pb         push_back
#define  pii        pair
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)
 
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 5e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;

set st;
pii p[maxn];
vector g[maxn];

void dfs(int u, int fa) {
    int len = g[u].size();
    for(int i=0; i

Cards

\[ Time Limit: 4 s\quad Memory Limit: 256 MB \]
留坑

你可能感兴趣的:(Educational Codeforces Round 78 (Rated for Div. 2) 题解)