先放模板。。。
#define lowbit(x) (x) & (-x)
const int N=1005;
const int M=1e9+7;
//【修改点(向上),求区间(向下)】の模板
int dp[N][N],c[NN][N];
int a[N],r[N],w[N];
bool cmp(int b,int c) {
return a[b]0){
s=(s+c[i][j])%M;
i-=lowbit(i);
}
return s%M;
}
int main(){
int t,cnt=0;
cin>>t;
while(t--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
memset(c,0,sizeof(c));
memset(dp,0,sizeof(dp));
for(int i=0;i<=n;++i)
r[i]=i; //存下标
sort(r+1,r+n+1,cmp); //下标根据a[]的大小排序
for(int i=1;i<=n;++i)
w[r[i]]=i; //把a[]哈希一下(原本400,500,600的会变成1,2,3)
for(int i = 1; i <= n; ++i) {
dp[w[i]][1]=1;
update(w[i],1,1);
for(int j=2;j<=m;++j) {
dp[w[i]][j]=sum(w[i]-1,j-1); //表示w数组到i之前末位小于w[i]的长度为j-1的子序列个数,即Σdp[k][j-1](1<=k
我也想过写成:
for(int j=2;j<=m;++j){
dp[id][j]=dp1[id-1][j-1];
dp1[id][j]+=dp1[id-1][j];
}
但id的值可能会跳跃的,比如上面的r[]={1,3,5,2,4},算第三个dp[5][j]+=dp1[4][j-1],但此时还没有dp1[4][]的值,所以不能累加。这时就体现出了树状数组的作用。
【求前缀和为k的下标位置,和sum()刚好相反】
int find(int k){
int cnt = 0, ans = 0;
for (int i = 20; i >= 0; --i){ //2^20大于50000
ans += (1 << i);
if (ans >= n || cnt + c1[ans] >= k) ans -= (1 << i);
else cnt += c1[ans];
}
return ans+1;
}
【修改点的值,求区间最值】
void update2(int ii,int val){ //修改点
w[ii]=val;
for(int i=ii; i<=n+5; i+=lowbit(i)){
if(val>c2[i])
c2[i]=val;
else
break;
}
}
int query(int l, int r){
int s=w[r];//上边界
while (l!=r){
for(r-=1;r-lowbit(r)>=l;r-=lowbit(r)){
s=max(s,c2[r]);//注意计算区间,不要夸区间
}
s=max(s,w[r]); //下边界
}
return s;
}
【POJ 2155】 http://poj.org/problem?id=2155 二维矩阵树状数组(修改区间,求点的值)
const int N=1005,NN=3000;
const int M=1e9+7;
int dp[N][N],c1[NN][NN];
int n,m,a,b,c,d;
void update(int ii,int jj,int val){ //修改区间(向下修改)
for(int i=ii; i>0; i-=lowbit(i)){
for(int j=jj; j>0; j-=lowbit(j)){
c1[i][j]=(c1[i][j]+val);
}
}
}
int sum(int ii,int jj){ //求某点的值(向上统计)
int s=0;
for(int i=ii; i<=NN; i+=lowbit(i)){
for(int j=jj; j<=NN; j+=lowbit(j)){
s+=c1[i][j];
}
}
return s;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
memset(c1,0,sizeof(c1));
char cc[2];
scanf("%d%d",&n,&m);
for(int i=0;i
【POJ2299】 求至少交换几次相邻元素使得数列递增(很难想到可以用树状数组做)http://poj.org/problem?id=2299
http://blog.csdn.net/lyy289065406/article/details/6647346
本质是冒泡排序,但却还可以用归并排序求解。。。http://www.cnblogs.com/gj-Acit/archive/2013/08/10/3250525.html
const int N=500005,NN=1500005;
const int M=1e9+7;
ll c1[NN];
int n,m;
ll a;
void update(ll ii,ll val){ //修改点
for(int i=ii; i<=NN; i+=lowbit(i)){
c1[i]=(c1[i]+val);
}
}
int sum(ll ii){ //求区间
ll s=0;
for(int i=ii; i>0; i-=lowbit(i)){
s+=c1[i];
}
return s;
}
int main(){
int n;
while(cin>>n&&n){
memset(c1,0,sizeof(c1));
ll s=0;
for(int i=0;i>a;
a++;
s+=i-sum(a-1);
update(a,1);
}
cout<
【POJ3321】 http://poj.org/problem?id=3321 (修改点,求区间值)
(题意转)给你一颗苹果树,树的主干设为1,每一个分支设为一个数,一直到N,代表这颗苹果树。每个分支上面只能最多有一个苹果,也就是一个枝子上面不可能有两个苹果,另外注意一点,不要把苹果树想象成二叉树,苹果树每个节点可以分出很多叉,应该是多叉树。
输入是叉之间的关系,
1 2
1 3
就是主干上面两个叉分别是2 和3.
下面是两种操作,Q 和C
C j 的意思是如果 j 这个枝子上面有苹果就摘下来,如果没有,那么就会长出新的一个
Q j 就是问 j 这个叉上面的苹果总数。
http://www.cnblogs.com/Jason-Damon/archive/2012/03/02/2376471.html
const int N=100005,NN=300005;
const int M=1e9+7;
int c1[NN];
vector > v(N);
//vector v[N]; 写成这样就会超时??
int f;
int y[N],st[N],ed[N];
void update(int ii,int val){
for(int i=ii; i<=NN; i+=lowbit(i)){
c1[i]=(c1[i]+val);
}
}
int sum(int ii){
int s=0;
for(int i=ii; i>0; i-=lowbit(i)){
s+=c1[i];
}
return s;
}
void dfs(int p){ //重新定义每个节点的标号,确定子树节点范围(关于这个的理解看链接)
st[p]=++f;
for(int i=0;i
hdu3450 lower_bound离散化大数值 http://acm.hdu.edu.cn/showproblem.php?pid=3450
给一些数,问有多少集合,满足相邻的数之间的差的绝对值小于d。
const int N=100005,NN=300005;
int x[N],y[N];
int c1[NN];
void update(int ii,int val){ //修改点
for(int i=ii; i<=NN; i+=lowbit(i)){
c1[i]=(c1[i]+val)%9901;
}
}
int sum(int ii){ //求区间
int s=0;
for(int i=ii; i>0; i-=lowbit(i)){
s=(s+c1[i])%9901;
}
return s;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)==2){
memset(c1,0,sizeof c1);
for(int i=1;i<=n;++i){
scanf("%d",&x[i]);
y[i]=x[i];
}
sort(y+1,y+n+1); //用y数组来离散化,避免值太大
for(int i=1;i<=n;++i){
int p=lower_bound(y+1,y+n+1,x[i]-m)-y; //取下界
int q=upper_bound(y+1,y+n+1,x[i]+m)-y-1; //取上界
//【注意了!!结果a-b是负数的话要写成((a-b)%mod+mod)%mod,不能省略】
int s=((sum(q+1)-sum(p-1+1))%9901+9901)%9901;
int h=lower_bound(y+1,y+n+1,x[i])-y;
update(h+1,(s+1)%9901);
}
printf("%d\n",((sum(n+1)-(n%9901))%9901+9901)%9901);
}
return 0;
}
hdu5592 给出数组a[],a[i]表示b[]的前i个数的逆序对个数,让你还原这个数组b[] http://acm.hdu.edu.cn/showproblem.php?pid=5592
const int N=50005,NN=50005;
int x[N];
int y[N],z[N],w[N];
int c1[NN],c2[NN];
int n;
void update(int ii,int val){ //修改点
for(int i=ii; i<=n+5; i+=lowbit(i)){
c1[i]=(c1[i]+val);
}
}
int find(int k){ //【求前缀和为k的下标位置。和sum()刚好相反】
int cnt = 0, ans = 0;
for (int i = 20; i >= 0; --i){ //2^20大于50000
ans += (1 << i);
if (ans >= n || cnt + c1[ans] >= k) ans -= (1 << i);
else cnt += c1[ans];
}
return ans+1;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
memset(c1,0,sizeof(c1));
memset(z,0,sizeof(z));
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&x[i]);
update(i,1);
}
for(int i=n;i>=2;--i){
int p=x[i]-x[i-1];
y[i]=find(i-p);
update(y[i],-1);
z[y[i]]=1;
}
for(int i=1;i<=n;++i){
if(z[i]==0)
y[1]=i;
}
for(int i=1;i<=n-1;++i)
printf("%d ",y[i]);
printf("%d\n",y[n]);
}
return 0;
}