题意:给定一个序列,从中选择偶数个数,满足某些性质,不改变本来的先后顺序,问有多少种选择方法。
选出的序列 (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
", ++kase, res);
}
return 0;
}