TOJ 3896 Above the Median -- 分治 树状数组

题目链接:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3896

题目大意:给定一个只有1和-1的数列,求连续非负子序列的个数。(当然原题不是这么直白的,要适当转化一下)

分析:很困。。。脑袋不清醒。。。完全忘了树状数组(这个写起来很简单)。于是纠结之下用分治做的,时间复杂度和树状数组是一样的。

假设现在求数列a[s..t]中的非负子序列个数,记为f(s, t)。令mid = (s + t) / 2,f(s, t) = f(s, mid) + f(mid + 1, t) + 包含a[mid]和a[mid+1]的子序列个数。为了计算第三部分,先统计a[mid+1..t]的前缀和出现的次数,用t[i]表示和不超过i的总数,再计算a[s..mid]的后缀和,若某个和为sum,那么有(t - mid - t[sum - 1])个满足条件的子序列。分治时间复杂度可以表示为:

f(n) = 2f(n / 2) + O(n)

也就是f(n) = nlogn,和树状数组一样。绕了好大一圈啊。。。。。

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
         #include 
         
           #include 
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                #include 
               
                 #include 
                
                  #include 
                 
                   #include 
                  
                    #include 
                   
                     #define mp make_pair #define X first #define Y second #define MEMSET(a, b) memset(a, b, sizeof(a)) using namespace std; typedef unsigned int ui; typedef long long ll; typedef unsigned long long ull; typedef pair 
                    
                      pii; typedef vector 
                     
                       vi; typedef vi::iterator vi_it; typedef map 
                      
                        mii; typedef priority_queue 
                       
                         pqi; typedef priority_queue 
                        
                          , greater 
                         
                           > rpqi; typedef priority_queue 
                          
                            pqp; typedef priority_queue 
                           
                             , greater 
                            
                              > rpqp; const int MAX_N = 100000 + 2; const int HALF = 50000 + 1; int a[MAX_N]; int sum[MAX_N]; int t[MAX_N]; ll cnt(int lft, int rht) { if (lft == rht) { return a[lft] == 1 ? 1 : 0; } int mid = (lft + rht) >> 1; ll ret = cnt(lft, mid) + cnt(mid + 1, rht); int i, j; for (i = HALF - mid + lft - 2; i <= HALF + rht - mid; ++i) { t[i] = 0; } sum[mid] = 0; for (i = mid + 1; i <= rht; ++i) { sum[i] = sum[i - 1] + a[i]; ++t[sum[i] + HALF]; } for (i = HALF - rht + mid + 1; i <= HALF + rht - mid; ++i) { t[i] += t[i - 1]; } assert(t[HALF + rht - mid] == rht - mid); sum[mid + 1] = 0; for (i = mid; i >= lft; --i) { sum[i] = sum[i + 1] + a[i]; ret += rht - mid - t[HALF - 1 - sum[i]]; } return ret; } int main(int argc, char *argv[]) { // freopen("D:\\in.txt", "r", stdin); int n, x, i; cin >> n >> x; for (i = 1; i <= n; ++i) { scanf("%d", a + i); a[i] = a[i] >= x ? 1 : -1; } printf("%I64d\n", cnt(1, n)); return 0; } 
                             
                            
                           
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
          
       
      
      
     
     
    
    
   
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值