PAT (Top Level) 解题报告

来源:互联网 发布:高晓松和吴彦祖 知乎 编辑:程序博客网 时间:2024/06/08 03:19

PAT (Top Level) 解题报告

1007. Red-black Tree (35)

题目描述

给N个非叶子节点,问这N个节点能组成的红黑树的个数。

解法

dp[i][j][k] 表示i个节点(不算叶子节点)的红黑树子树 黑树高(路径上黑色节点个数且不算叶子节点)为j 根节点颜色为k的个数。

dp[i][j][RED]=dp[iL][j][BLK]×dp[iiL1][j][BLK]
dp[i][j][BLK]=(dp[iL][j1][BLK]+dp[iL][j1][RED])×(dp[iiL1][j1][BLK]+dp[iiL1][j1][RED])

需要注意的一点是,j不用全部枚举(不然会T1组数据),只枚举 [log(i+1)/2,log(i+1)+1] 即可。
最小的情况是红黑间隔(显然),最大的情况的证明:假设存在点数为n,路径深度为log(n+1)+1的路径,那么节点个数最少为2(n+1)-1>n,矛盾)

//dp 求有n个区间节点的红黑树的个数//dp[i][j][k] 表示i个节点(不算叶子节点)的红黑树子树 //黑树高(路径上黑色节点个数且不算叶子节点)为j 根节点颜色为k的个数#include<bits/stdc++.h>using namespace std;const int mod = 1000000007;const int N = 505;const int BLK = 0, RED = 1;int dp[N][N][2];using ll = long long;int main() {    int n;    scanf("%d",&n);    dp[1][1][BLK] = dp[1][0][RED] = dp[0][0][BLK] = 1;    for(int i = 2; i <= n; i++) {        for(int j = log2(i+1)/2; j <= log2(i+1)+1; j++) {            for(int il = 0; il < i/2; il++) {                dp[i][j][RED] = (ll(dp[i][j][RED]) + 1ll*dp[il][j][BLK]*dp[i-il-1][j][BLK]*2) % mod;                dp[i][j][BLK] = (ll(dp[i][j][BLK]) +                         1ll*(dp[il][j-1][BLK] + dp[il][j-1][RED]) *                         (dp[i-il-1][j-1][BLK] + dp[i-il-1][j-1][RED])*2) % mod;            }            if(i & 1) {                int il = i / 2;                dp[i][j][RED] = (ll(dp[i][j][RED]) + 1ll*dp[il][j][BLK]*dp[i-il-1][j][BLK]) % mod;                dp[i][j][BLK] = (ll(dp[i][j][BLK]) +                         1ll*(dp[il][j-1][BLK] + dp[il][j-1][RED]) *                         (dp[i-il-1][j-1][BLK] + dp[i-il-1][j-1][RED])) % mod;            }        }    }    int res = 0;    for(int i = 1; i <= n; i++) res = (res + dp[n][i][BLK]) % mod;    printf("%d\n",res);    return 0;}

1008. Airline Routes (35)

题目描述

给个图问两个点是否有双向通路。

解法

求强连通分量。

#include<bits/stdc++.h>using namespace std;//求强连通 加fa为双连通namespace Tarjan {    const int MAXV =10005;    stack<int> st;    vector<int> E[MAXV];    bool inst[MAXV];    int TJ = 0;    int belong[MAXV];    int dfn[MAXV];    int low[MAXV];    int num = 0;    void tarjan(int u)    {        dfn[u] = low[u] = ++num;        st.push(u);        inst[u] = true;        vector<int>::iterator it;        for(it = E[u].begin();it!=E[u].end();it++)        {            int v = *it;            if(!dfn[v])            {                tarjan(v);                low[u] = min(low[u],low[v]);            }            else if(inst[v])            {                low[u] = min(low[u],dfn[v]);            }        }        //printf("------u=%d\n",u);        if(dfn[u] == low[u])        {            TJ++;            int v;            do            {                v = st.top();                st.pop();                inst[v] = false;                belong[v] = TJ;                //v为强连通分量的元素            }while(v!=u);        }    }    void init() {        memset(dfn, 0, sizeof(dfn));        memset(low, 0, sizeof(low));        num = 0;    }};using namespace Tarjan;int main() {    int n, m;    scanf("%d%d",&n,&m);    init();    while(m--) {        int a, b;        scanf("%d%d",&a,&b);        Tarjan::E[a].push_back(b);    }    tarjan(1);    int K;    scanf("%d",&K);    while(K--) {        int a, b;        scanf("%d%d",&a,&b);        if(belong[a] == belong[b]) printf("Yes\n");        else printf("No\n");    }}

1010. Lehmer Code (35)

题目描述

求任意位置开始的逆序对个数。

解法

经典树状数组题。

    #include<bits/stdc++.h>    using namespace std;    const int N = 1e5 + 5;    using p = pair<int,int>;    int n, s[N], res[N];    p a[N];    inline int lowbit(int x) {        return x&-x;    }    inline void _add(int x, int v) {        while(x <= n) {            s[x] += v;            x += lowbit(x);        }    }    inline int _sum(int x) {        int res = 0;        while(x) {            res += s[x];            x -= lowbit(x);        }        return res;    }    int main() {        scanf("%d",&n);        for(int i = 1; i <= n; i++) {            scanf("%d",&a[i].first);            a[i].second = i;        }        sort(a + 1, a + 1 + n);        for(int i = 1; i <= n; i++) {            res[a[i].second] = _sum(n) - _sum(a[i].second);            _add(a[i].second, 1);        }        for(int i = 1; i <= n; i++) {            printf("%d%c",res[i]," \n"[i==n]);        }    }

1016. Uniqueness of MST (35)

题目描述

求MST是否唯一。

解法

枚举MST上的边,看是否能找不经过这条边且与原MST权值相等的MST。

#include<bits/stdc++.h>using namespace std;const int N = 505;int fa[N];int tot = 0;void init(int n) {    tot = n;    for(int i = 1; i <= n; i++) fa[i] = i;}int find(int x) {    if(fa[x] == x) return x;    else return fa[x] = find(fa[x]);}void un(int x, int y) {    if( (x=find(x))==(y=find(y)) ) return;    fa[x] = y;    tot--;}using p = pair<int,int>;vector<p> E[N];using tu = tuple<int,int,int>;tu A[250005];int gg[250005];int me[N], mtot = 0;int main() {    int n, m, sum = 0;    scanf("%d%d",&n,&m);    init(n);    for(int i = 1; i <= m; i++) {        int a, b, c;        scanf("%d%d%d",&a,&b,&c);        A[i] = tu(c,a,b);        E[a].push_back(p(b,c));        E[b].push_back(p(a,c));        un(a, b);        sum += c;    }    if(tot != 1) {        printf("No MST\n%d\n",tot);        return 0;    }    if(m == n - 1) {        printf("%d\nYes\n",sum);        return 0;    }    sort(A + 1, A + m + 1);    init(n);    sum = 0;    for(int i = 1; i <= m; i++) {        int v, a, b;        tie(v, a, b) = A[i];        if(find(a) == find(b)) {}        else {            un(a,b);            sum += v;            me[mtot++] = i;        }    }    printf("%d\n",sum);    for(int i = 0; i < mtot; i++) {        gg[me[i]] = 1;        int temp = 0;        init(n);        for(int j = 1; j <= m; j++) {            if(gg[j]) continue;            int v, a, b;            tie(v, a, b) = A[j];            if(find(a) == find(b)) {}            else {                un(a,b);                temp += v;            }        }        if(temp == sum) {            printf("No\n");            return 0;        }         gg[me[i]] = 0;    }     printf("Yes\n");    return 0;}
阅读全文
0 0
原创粉丝点击