• POJ 3387 Crazy Thairs


    POJ_3378

        如果设f[i][j]表示第i个数选a[j]时的方案数,那么f[i][j]就等于所有满足a[k]<a[j]的f[i-1][k]之和,为了能够快速的求出这个和,可以在循环i-1的时候就将所有的f[i-1][k]放到线段树、树状数组或者平衡树上去即可。如果用线段树或者树状数组统计的话,需要将a[]的值离散化。

        此外,在计算中间结果时5000^4是不会超long long的,但是最后合并的时候需要用到高精度加法。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define MAXD 50010
    int N, T, node, left[MAXD], right[MAXD], a[MAXD], key[MAXD], size[MAXD];
    long long int sum[MAXD], num[MAXD], wa[MAXD], wb[MAXD], *f, *g;
    struct BigInteger
    {
    int a[30];
    void init(long long int n)
    {
    int i;
    for(i = 0; i < 30; i ++)
    {
    a[i] = n % 10;
    n /= 10;
    }
    }
    BigInteger add(BigInteger &b)
    {
    int i, s, c = 0;
    BigInteger ans;
    for(i = 0; i < 30; i ++)
    {
    s = a[i] + b.a[i] + c;
    ans.a[i] = s % 10;
    c = s / 10;
    }
    return ans;
    }
    void print()
    {
    int i;
    for(i = 29; i > 0; i --)
    if(a[i])
    break;
    for(; i >= 0; i --)
    printf("%d", a[i]);
    printf("\n");
    }
    };
    void leftrotate(int &T)
    {
    int k = right[T];
    right[T] = left[k];
    left[k] = T;
    size[k] = size[T];
    size[T] = size[left[T]] + size[right[T]] + 1;
    sum[k] = sum[T];
    sum[T] = sum[left[T]] + sum[right[T]] + num[T];
    T = k;
    }
    void rightrotate(int &T)
    {
    int k = left[T];
    left[T] = right[k];
    right[k] = T;
    size[k] = size[T];
    size[T] = size[left[T]] + size[right[T]] + 1;
    sum[k] = sum[T];
    sum[T] = sum[left[T]] + sum[right[T]] + num[T];
    T = k;
    }
    void maintain(int &T, int flag)
    {
    if(flag == 0)
    {
    if(size[left[left[T]]] > size[right[T]])
    rightrotate(T);
    else if(size[right[left[T]]] > size[right[T]])
    leftrotate(left[T]), rightrotate(T);
    else
    return ;
    }
    else
    {
    if(size[right[right[T]]] > size[left[T]])
    leftrotate(T);
    else if(size[left[right[T]]] > size[left[T]])
    rightrotate(right[T]), leftrotate(T);
    else
    return ;
    }
    maintain(left[T], 0);
    maintain(right[T], 1);
    maintain(T, 0);
    maintain(T, 1);
    }
    void init()
    {
    int i;
    for(i = 1; i <= N; i ++)
    scanf("%d", &a[i]);
    }
    long long int getsum(int &T, int v)
    {
    if(T == 0)
    return 0;
    if(v <= key[T])
    return getsum(left[T], v);
    else
    return getsum(right[T], v) + sum[left[T]] + num[T];
    }
    void newnode(int &T, long long int n, int v)
    {
    T = ++ node;
    key[T] = v;
    size[T] = 1;
    sum[T] = num[T] = n;
    left[T] = right[T] = 0;
    }
    void Insert(int &T, long long int n, int v)
    {
    if(T == 0)
    {
    newnode(T, n, v);
    return ;
    }
    ++ size[T];
    sum[T] += n;
    if(v < key[T])
    Insert(left[T], n, v);
    else
    Insert(right[T], n, v);
    maintain(T, v >= key[T]);
    }
    void solve()
    {
    int i, j, k;
    long long int *t;
    BigInteger ans, x;
    f = wa, g = wb;
    for(i = 1; i <= N; i ++)
    g[i] = 1;
    for(i = 2; i <= 5; i ++)
    {
    T = node = size[0] = left[0] = right[0] = 0;
    for(j = 1; j <= N; j ++)
    {
    f[j] = getsum(T, a[j]);
    Insert(T, g[j], a[j]);
    }
    t = f, f = g, g = t;
    }
    ans.init(0);
    for(i = 1; i <= N; i ++)
    {
    x.init(g[i]);
    ans = ans.add(x);
    }
    ans.print();
    }
    int main()
    {
    while(scanf("%d", &N) == 1)
    {
    init();
    solve();
    }
    return 0;
    }


  • 相关阅读:
    求数组中的最小子数组,时间复杂度o(n),java
    第四周进度条
    四则混合运算3
    软件工程作业3
    《构建之法》第三周阅读笔记
    第三周学习进度
    学习进度01
    构建之法阅读笔记01
    构建之法问题
    随机生成题目运算
  • 原文地址:https://www.cnblogs.com/staginner/p/2430207.html
Copyright © 2020-2023  润新知