LightOJ 1343 - Aladdin and the Black Stones 二维树状数组

题目链接


题意:给定一个序列,从中选择偶数个数,满足某些性质,不改变本来的先后顺序,问有多少种选择方法。
选出的序列 \(w_1,w_2,w_3,\cdots,w_{2m}\),需要满足性质:

\(w_1+w_{2m} > w_2 + w_{2m-1} > \cdots > w_m + w_{m+1}\)

其实如果不是分类的题的话,是很难想到这样做的。

思路:

将所有的\(w_i+w_j\)处理出来。

dp的思路: dp[i][j]表示以i为下界,以j为上界能组成的序列个数

\[dp[i][j] = \sum_{i<x<y<j}dp[x][y] + 1 \]

利用二维树状数组来快速的得到转移方程右边的求和公式。将所有的\(w_i+w_j\)处理成三元组(i,j,val),按照val排序,val相同按照i从小到大排,i相同按照j从大到小排,保证先处理值最小,而且区间大的(这里为了保证如果值相同的时候,统计可行序对不会把值相同的序对算进去)。

寻找序对(i,j)的方式是统计以(i,i)为左下角,(j,j)为右上角的矩形中的数值和,每次得到答案,就更新矩形(i,j)处的值。

类似于那个求最长上升子序列个数的题目(树状数组+DP)的思想


#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
#include <string>
#include <bitset>
#include <ctype.h>
using namespace std;
typedef pair<int,int> P;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int N = 700 + 5;
const LL mod = 1LL << 32;

int n;
LL c[N][N];
inline int lowbit(int i)
{
    return i&(-i);
}
void add(int x, int y, int val)
{
    for(int i = x; i <= n; i += lowbit(i))
    {
        for(int j = y; j <= n; j += lowbit(j))
            c[i][j] = (c[i][j] + val)%mod;
    }
}
LL sum(int x, int y)
{
    LL ans = 0;
    for(int i = x; i > 0; i -= lowbit(i))
    {
        for(int j = y; j > 0; j -= lowbit(j))
            ans = (c[i][j] + ans)%mod;
    }
    return ans;
}


struct Node
{
    int x,y;
    LL sum;
    Node(){}
    Node(int _x, int _y, LL s)
    {
        x = _x; y = _y;
        sum = s;
    }
};
bool cmp(Node a, Node b)
{
    if(a.sum == b.sum)
    {
        return a.x == b.x ? a.y>b.y : a.x<b.x;
    }
    return a.sum < b.sum;
}
vector<Node> tmp;
int t, kase = 0;
LL a[N];
int main()
{
    scanf("%d", &t);
    while(t--)
    {
        tmp.clear();
        scanf("%d", &n);
        memset(c, 0, sizeof(c));
        for(int i = 1; i <= n; i++)
        {
            scanf("%lld", &a[i]);
        }
        for(int i = 1; i <= n; i++)
        {
            for(int j = i+1; j <= n; j++)
            {
                tmp.push_back(Node(i,j,(a[i]+a[j])%mod));
            }
        }
        sort(tmp.begin(), tmp.end(), cmp);
        LL res = 0;
        for(int i = 0; i < tmp.size(); i++)
        {
            int x = tmp[i].x, y = tmp[i].y;
            LL ans = (sum(y-1,y-1) - sum(x,y-1) - sum(y-1, x) + sum(x,x) + 4*mod) % mod;
            ans = (ans + 1)%mod;
            add(x,y,ans);
            res += ans;
            res %= mod;
        }
        printf("Case %d: %lld\n", ++kase, res);
    }
    return 0;
}
posted @ 2017-09-03 21:43  可达龙  阅读(278)  评论(0编辑  收藏  举报