zoukankan      html  css  js  c++  java
  • 【AtCoder】ARC097 (C

    C - K-th Substring

    题解

    找出第K大的子串,重复的不计入

    这个数据范围可能有什么暴力可以艹过去吧,但是K放大的话这就是后缀自动机板子题啊= =

    代码

    #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('
    ');
    }
    

    D - Equals

    题解

    给出可交换的两个位置,和一个排列,求最后能达成pi = i的位置

    直接用并查集维护连通性,判一下这个位置上的数和该到的位置和初始位置在不在一个联通块

    代码

    #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
    ",cnt);
    }
    

    E - Sorted and Sorted

    题解

    给出一个黑棋N个白棋N个的排列,每一种颜色的球分别标上1 - N,每次可以交换相邻两个球,求白棋相对顺序正确并且黑棋相对顺序正确,所需要最少的步数

    动态规划,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同理
    这个可以用树状数组预处理出来

    代码

    #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
    ",dp[N][N]);
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    

    F - Monochrome Cat

    题解

    有一只猫,还有一个树(多么现实的故事),树上黑白两种颜色,猫可以选择一个点开始走,每秒可以选择两种事件中的一种
    1.翻转当前点颜色
    2.到一个相邻点,并必须翻转这个点的颜色

    树dp,分三个路径,G[u]表示从点出发到这个点的子树并且不回来,F[u]表示从这个点出发并且回到这个点,H[u]表示一条路径经过这个点并且起点和终点都在它的子树中

    转移比较繁琐但是很显然,具体看代码

    代码

    #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
    ",ans);
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
        return 0;
    }
    
  • 相关阅读:
    第01组 团队Git现场编程实战
    第01组 团队项目-需求分析报告
    团队项目-选题报告
    第二次结对编程作业
    第1组 团队展示
    第一次结对编程作业
    第一次博客作业
    2019 SDN上机第1次作业
    第08组 团队项目-需求分析报告
    团队项目-选题报告
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9050688.html
Copyright © 2011-2022 走看看