PAT (Top Level) 解题报告

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
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
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
    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
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

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; }

你可能感兴趣的:(PAT)