【AtCoder】ARC097 (C - F)題解

C - K-th Substring

題解

找出第K大的子串,重複的不計入node

這個數據範圍可能有什麼暴力能夠艹過去吧,可是K放大的話這就是後綴自動機板子題啊= =ios

代碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
//#define ivorysi
#define MAXN 5005
#define eps 1e-8
using namespace std;
typedef long long int64;
typedef double db;
struct node {
    int len,cnt,f;
    node *par,*nxt[26];
}pool[MAXN * 3],*tail = pool,*root,*last;
void Build_Sam(int len,int c) {
    node *nowp = tail++,*p;
    nowp->len = len;
    for(p = last ; p && !p->nxt[c] ; p = p->par) {
        p->nxt[c] = nowp;
    }
    if(!p) nowp->par = root;
    else {
        node *q = p->nxt[c];
        if(q->len == p->len + 1) nowp->par = q;
        else {
            node *cp = tail++;
            *cp = *q;cp->cnt = 0;cp->len = p->len + 1;
            q->par = nowp->par = cp;
            for( ; p && p->nxt[c] == q ; p = p->par) p->nxt[c] = cp;
        }
    }
    last = nowp;
}
int c[MAXN];
node *que[MAXN * 3];
char s[MAXN];
int N,K,M;
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    root = last = tail++;
    scanf("%s%d",s + 1,&K);
    N = strlen(s + 1);
    for(int i = 1 ; i <= N ; ++i) {
        Build_Sam(i,s[i] - 'a');
    }
    M = tail - pool;
    for(int i = 0 ; i < M ; ++i) {
        c[pool[i].len]++;
    }
    for(int i = 1 ; i <= N ; ++i) c[i] += c[i - 1];
    for(int i = 0 ; i < M ; ++i) {
        que[c[pool[i].len]--] = &pool[i];
    }
    for(int i = 1 ; i <= M ; ++i) que[i]->f = 1;
    for(int i = M ; i >= 1 ; --i) {
        for(int j = 0 ; j < 26 ; ++j) {
            if(que[i]->nxt[j])
            que[i]->f += que[i]->nxt[j]->f;
        }
    }
    node *p = root;
    while(K > 0) {
        for(int i = 0 ; i < 26 ; ++i) {
            if(!p->nxt[i]) continue;
            if(K <= p->nxt[i]->f) {
            putchar('a' + i);
            p = p->nxt[i];
            --K;
            break;
            }
            else K -= p->nxt[i]->f;
        }
    }
    putchar('\n');
}

D - Equals

題解

給出可交換的兩個位置,和一個排列,求最後能達成pi = i的位置chrome

直接用並查集維護連通性,判一下這個位置上的數和該到的位置和初始位置在不在一個聯通塊數組

代碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
//#define ivorysi
#define MAXN 100005
#define eps 1e-8
#define pb push_back
using namespace std;
typedef long long int64;
typedef double db;
int N,M;
int P[MAXN],fa[MAXN];
int getfa(int x) {
    return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    scanf("%d%d",&N,&M);
    for(int i = 1 ; i <= N ; ++i) scanf("%d",&P[i]);
    for(int i = 1 ; i <= N ; ++i) fa[i] = i;
    int x,y;
    for(int i = 1 ; i <= M ; ++i) {
        scanf("%d%d",&x,&y);
        fa[getfa(x)] = getfa(y);
    }
    int cnt = 0;
    for(int i = 1 ; i <= N ; ++i) {
        if(getfa(P[i]) == getfa(i)) ++cnt;
    }
    printf("%d\n",cnt);
}

E - Sorted and Sorted

題解

給出一個黑棋N個白棋N個的排列,每一種顏色的球分別標上1 - N,每次能夠交換相鄰兩個球,求白棋相對順序正確而且黑棋相對順序正確,所須要最少的步數ui

動態規劃,dp[i][j]表示前邊放了i個白棋和j個黑棋所須要的最少步數
dp[i][j] = min(dp[i - 1][j] + cost_w[i - 1][j] , dp[i][j - 1] + cost_b[i][j - 1])
cost_w[i][j]表示前面已經有i個白棋和j個黑棋,在序列末再填一個白棋所須要的步數,cost_b同理
這個能夠用樹狀數組預處理出來spa

代碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
//#define ivorysi
#define MAXN 2005
#define eps 1e-7
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
int N,a[MAXN * 2];
char c[MAXN * 2][5];
int tr[2][MAXN],cost[2][MAXN][MAXN],dp[MAXN][MAXN];
int lowbit(int x) {return x & (-x);}
void Insert(int id,int x) {
    while(x <= N) {
        tr[id][x]++;
        x += lowbit(x);
    }
}
int Query(int id,int x) {
    int res = 0;
    while(x > 0) {
        res += tr[id][x];
        x -= lowbit(x);
    }
    return res;
}
void Solve() {
    scanf("%d",&N);
    for(int i = 1 ; i <= 2 * N ; ++i) {
        scanf("%s%d",c[i] + 1,&a[i]);
    }
    for(int i = 1 ; i <= 2 * N ; ++i) {
        if(c[i][1] == 'W') {
            for(int j = 0 ; j <= N ; ++j) {
            cost[0][a[i] - 1][j] = (i - 1) - Query(0,a[i] - 1) - Query(1,j);
            }
            Insert(0,a[i]);
        }
        else {
            for(int j = 0 ; j <= N ; ++j) {
            cost[1][j][a[i] - 1] =  (i - 1) - Query(0,j) - Query(1,a[i] - 1);
            }
            Insert(1,a[i]);
        }
    }
    for(int i = 0 ; i <= N ; ++i) {
        for(int j = 0 ; j <= N ; ++j) {
            if(i == 0 && j == 0) continue;
            dp[i][j] = 0x7fffffff;
            if(i != 0) {
            dp[i][j] = min(dp[i][j],dp[i - 1][j] + cost[0][i - 1][j]);
            }
            if(j != 0) {
            dp[i][j] = min(dp[i][j],dp[i][j - 1] + cost[1][i][j - 1]);
            }
        }
    }
    printf("%d\n",dp[N][N]);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

F - Monochrome Cat

題解

有一隻貓,還有一個樹(多麼現實的故事),樹上黑白兩種顏色,貓能夠選擇一個點開始走,每秒能夠選擇兩種事件中的一種
1.翻轉當前點顏色
2.到一個相鄰點,並必須翻轉這個點的顏色code

樹dp,分三個路徑,G[u]表示從點出發到這個點的子樹而且不回來,F[u]表示從這個點出發而且回到這個點,H[u]表示一條路徑通過這個點而且起點和終點都在它的子樹中事件

轉移比較繁瑣可是很顯然,具體看代碼get

代碼

#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <cstring>
#include <ctime>
#include <map>
#include <algorithm>
#include <cmath>
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long int64;
typedef double db;
int N;
struct node {
    int to,next;
}E[MAXN * 2];
int head[MAXN],sumE,sizW[MAXN];
int F[MAXN],G[MAXN],H[MAXN],ans,son[MAXN],fa[MAXN],Ah[MAXN];
char c[MAXN];
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
void addtwo(int u,int v) {
    add(u,v);add(v,u);
}
void dfs(int u) {
    if(c[u] == 'W') sizW[u] = 1;
    else sizW[u] = 0;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa[u]) {
        fa[v] = u;
        dfs(v);
        sizW[u] += sizW[v];
    }
    }
}
void dfs1(int u,int fa) {
    int Sum = 0;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa && sizW[v]) {
        dfs1(v,u);
        ++son[u];
        F[u] += F[v];
        Sum += F[v];
    }
    }
    if(!son[u] && c[u] == 'W') {
    G[u] = F[u] = 1;return;
    }
    F[u] += son[u] + 1;
    if(c[u] == 'W') F[u] += ((son[u] + 1) ^ 1) & 1;
    else F[u] += (son[u] + 1 & 1);
    G[u] = Sum;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa && sizW[v]) {
        G[u] = min(G[u],Sum - F[v] + G[v]);
    }
    }
    G[u] += son[u];
    if(c[u] == 'W') G[u] += (son[u] ^ 1) & 1;
    else G[u] += son[u] & 1;
    G[u] = min(G[u],F[u]);
    H[u] = 0x7fffffff;
    if(son[u] != 1) {
            
    pii t = mp(0,0);
    for(int i = head[u] ; i ; i = E[i].next) {
        int v = E[i].to;
        if(v != fa && sizW[v]) {
        if(F[v] - G[v] > t.se) t.se = F[v] - G[v];
        if(t.se > t.fi) swap(t.se,t.fi);
        }
    }
    int tmp = c[u] == 'W' ? ((son[u] - 1) ^ 1) & 1 : (son[u] - 1) & 1;
    H[u] = Sum - t.fi - t.se + tmp + son[u] - 1;
    Ah[u] = tmp;
    }
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa && sizW[v]) {
        int tmp = Sum - F[v] + H[v] + 1 - Ah[v] + (Ah[v] ^ 1) + son[u];
        int t = c[u] == 'W' ? (son[u] ^ 1) & 1 : son[u] & 1;
        if(tmp + t < H[u]) {
        H[u] = tmp + t;Ah[u] = t;
        }
    }
    }
}
void Init() {
    scanf("%d",&N);
    int u,v;
    for(int i = 1 ; i < N ; ++i) {
    scanf("%d%d",&u,&v);
    addtwo(u,v);
    }
    scanf("%s",c + 1);
    dfs(1);
}
void Solve() {
    ans = 0x7fffffff;
    dfs1(1,0);
    if(sizW[1] == 0) ans = 0;
    else if(sizW[1] == 1) ans = 1;
    else {
    for(int i = 1 ; i <= N ; ++i) {
        if(sizW[i] == sizW[1]) {
        ans = min(ans,G[i]);
        ans = min(ans,F[i]);
        ans = min(ans,H[i]);
        }
    }
    }
    printf("%d\n",ans);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
    return 0;
}
相關文章
相關標籤/搜索