HDU 4913 (思路题目)

题目意思是给定序列长度同为n的数列a,b;

要求出所有的子集元素的 2 ^ (max(a) ) * 3 ^ (max(b))的和。

分析:

首先对只有一个数组a,我们的通常思路是先排序 , 递推算法求解。 ans[ i ]  = ans[ i-1 ] + 2^(i-1) * 2^a[ i ];

那么多了一个b数组,可以先按b排序 。

记走到 i , 前面 a的值比ai小的有x个, 比 ai 大的 位置为 p1 , p2 , ... pk.

那么 走到i,只需统计 i 必选的和。

ans[ i ] = ans[ i-1 ] + (2^x * 2^ai  +  2^x*2^ap1 + 2^(x+1)*2^ap2 + .... + 2^(x+k-1)*2^apk) * 3^bi;

这样先给每个a[ i ] 一个rank(ai越小rank越小) ,加入线段树,维护2^(x)*2^ai, 其中x代表走到i时,比ai小的aj 有几个。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#define ls rt<<1
#define rs rt<<1|1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
#define rep(i,n) for(int i=0;i<(int) n; i++)
#define rep1(i,x,y) for(int i=x;i<=(int)y; i++)

const int maxn = 1e5 + 100;
const ll mod = 1e9 + 7;
struct node{
   ll sum, cnt;
}a[maxn<<2];
int n; ll col[maxn<<2];
ll pow_(int nn,int b){
   ll ans = 1 , te = nn;
   while(b){
       if(b&1) ans=ans*te%mod;
       b>>=1;
       te=te*te%mod;
   }
   return ans;
}
void push_up(int rt){
  a[rt].cnt = a[ls].cnt+a[rs].cnt;
  a[rt].sum = (a[ls].sum+a[rs].sum)%mod;
}
void push_down(int rt){
   if(col[rt] > 1){
      col[ls] = (col[ls]*col[rt])%mod;
      col[rs] = (col[rs]*col[rt])%mod;
      a[ls].sum = a[ls].sum*col[rt]%mod;
      a[rs].sum = a[rs].sum*col[rt]%mod;
      col[rt] = 1;
   }
}
void build(int l,int r,int rt){
    a[rt].sum = a[rt].cnt = 0; col[rt] = 1;
    if(l == r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void mul(int l,int r,int rt,int L,int R){
   if(L<=l&&r<=R){
      a[rt].sum = a[rt].sum*2%mod;
      col[rt]=col[rt]*2%mod;
      return ;
   }
   push_down(rt);
   int m=(l+r)>>1;
   if(L<=m) mul(lson,L,R);
   if(R> m) mul(rson,L,R);
   push_up(rt);
}
int query_cnt(int l,int r,int rt,int L,int R){
   if(L<=l&&r<=R)
      return a[rt].cnt;
   push_down(rt);
   int m=(l+r)>>1 , all = 0;
   if(L<=m) all += query_cnt(lson,L,R);
   if(R> m) all += query_cnt(rson,L,R);
   return all;
}
ll query_sum(int l,int r,int rt,int L,int R){
   if(L<=l&&r<=R)
      return a[rt].sum;
   push_down(rt);
   int m=(l+r)>>1 ; ll all = 0;
   if(L<=m) all += query_sum(lson,L,R);
   if(R> m) all = (all+query_sum(rson,L,R))%mod;
   return all;
}
void update(int l,int r,int rt,int p,int aa){
   if(l==r){
      a[rt].cnt = 1;
      ll x = (l==1 ? 0 : query_cnt(1,n,1,1,l-1));
      a[rt].sum = pow_(2,x+aa);
      return ;
   }
   push_down(rt);
   int m=(l+r)>>1;
   if(p <= m) update(lson,p,aa);
   if(p >  m) update(rson,p,aa);
   push_up(rt);
}
struct node2{
   int a,b,id;
}st[maxn];
int cmp1(node2 A, node2 B){ return  A.a < B.a;}
map<int,int> Rank;
int cmp2(node2 A, node2 B){ return A.b < B.b; }
int main()
{
   while(scanf("%d",&n)==1){
      build(1,n,1);
      rep1(i,1,n) scanf("%d %d",&st[i].a,&st[i].b),st[i].id = i;
      sort(st+1,st+1+n,cmp1);
      Rank.clear();
      rep1(i,1,n) Rank[st[i].id] = i ;
      sort(st+1,st+1+n,cmp2);
      ll ans = 0;
      rep1(i,1,n){
         update(1,n,1,Rank[st[i].id],st[i].a);
         ans = (ans + query_sum(1,n,1,Rank[st[i].id],n)*pow_(3,st[i].b)%mod)%mod;
         if(Rank[st[i].id]+1 <= n) mul(1,n,1,Rank[st[i].id]+1,n);
      }
      printf("%I64d\n",ans);
   }
   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值