1. 程式人生 > >Codeforces Round #423 (Div. 2) C 思維,並查集 或 線段樹 D 樹構造,水

Codeforces Round #423 (Div. 2) C 思維,並查集 或 線段樹 D 樹構造,水

closed alt pda memset sed () back ref cup

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals)

C. String Reconstruction 思維,並查集 或 線段樹

題意:一個字符串被刪除了,但給出 n條信息,要還原出可能的字典序最小的字符串。信息有:字符串ti,ki個位置xi,表明原本的字符串在xi位置是以字符串ti開頭的。

tags:慘遭 fst,一開始把所有字符串都存下來,排序做的,結果爆內存了。。

方法1: 考慮並查集,對於字符串 ti,在位置xi,字符串長度為len,更新之後,ti~(ti+len-1)位置的祖先就都指向ti+len。

技術分享
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define
fi first #define se second typedef long long ll; const int N = 2000005; int n, fa[N], ki, xi; char si[N], ans[N]; int Find(int x) { return fa[x]==x ? x : fa[x]=Find(fa[x]); } int main() { scanf("%d", &n); rep(i,1,N-1) fa[i]=i, ans[i]=a; int mx=0; rep(cn,1,n) { scanf(
"%s %d", si+1, &ki); int len=strlen(si+1); rep(ck,1,ki) { scanf("%d", &xi); mx=max(mx, xi+len-1); int y=xi; while((y=Find(y)) <= xi+len-1) { ans[y]=si[y-xi+1]; fa[y]=y+1; } } } rep(i,1,mx) putchar(ans[i]); return 0; }
View Code

方法2: 直接樹狀數組或線段樹更新

技術分享
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2001000;
char ans[maxn];
char c[maxn];
long long   t[maxn];

void add(int k)
{
    while(k < maxn)
    {
        t[k]++;
        k += k & -k;
    }
}
int sum(int x)
{
    long long  sum = 0;
    while(x)
    {
        sum += t[x];
        x -= x & -x;
    }
    return sum;
}
void updata(int l, int r, int k)
{
    if(l == r)
    {
        if(!ans[l])
        {
            add(l);
            ans[l] = c[k];
        }
        return ;
    }
    int mid = (l + r) >> 1;
    if(sum(mid)-sum(l-1) != mid - l + 1)
        updata(l, mid, k);
    if(sum(r)-sum(mid) != r - mid)
        updata(mid + 1, r, k + mid - l + 1);
}
int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        int lans = 0;
        memset(ans,0,sizeof(ans));
        memset(t,0,sizeof(t));
        while(n--)
        {
            int m = 0;
            scanf("%s%d", c, &m);
            int len = strlen(c);
            for(int i = 0; i < m; i++)
            {
                int l;
                scanf("%d", &l);
                lans = max(lans, l + len);
                updata(l, l + len-1, 0);
            }
        }
        for(int i = 1; i < lans; i++)
        {
            putchar(ans[i]? ans[i]: a);
        }
        printf("\n");
    }
    return 0;
}
View Code

D. High Load 樹構造,水,dfs

題意:n個點的樹,已知有k個葉子節點,要使得樹上的最長鏈最短,構造出這樹。

tags:大水題,比賽的時候竟然沒去看。。

技術分享
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 200005;

ll n, k;
vector<ll > G[N];
void dfs(int u, int fa)
{
    for(auto to : G[u]) if(to!=fa)
    {
        printf("%d %d\n", u, to);
        dfs(to, u);
    }
}
int main()
{
    scanf("%lld %lld", &n, &k);
    ll cnt=1, j;
    while(cnt<n)
    {
        for(j=1; j<=k, cnt+j<=n; ++j)
        {
            ll u=max(1LL, cnt+j-k);
            G[u].PB(cnt+j); G[cnt+j].PB(u);
        }
        cnt=cnt+j;
    }
    ll ans=(n-1+k-1)/k*2;
    if(n-1-k*(ans/2-1)==1) --ans;
    printf("%lld\n", ans);
    dfs(1, 0);

    return 0;
}
View Code

Codeforces Round #423 (Div. 2) C 思維,並查集 或 線段樹 D 樹構造,水