whu 1470 Join in tasks 计算推理

对于序列 a_1,a_2,..a_i.,a_n 从小到大排列处理花费会最小。

一个一个处理完,例如当处理 a_1

  则此时花费分为 a_1, 以及 a_x  (x>1)的花费来计算

    1. a_1 时   

    2. a_x 时  

  当消除掉 a_1 后,又生成一个新的 序列 a_1`, a_2`, ..., a_n`

  此时可以知道,  a_i` = a_i - a_1 + 1

  我们可以通过 线段树来 维护更新序列,这样省事. 但是这题 n = 1e5 , 且极限T = 100, 此时时间复杂度达到 1e7,

若再添加个 log(N) 复杂度,就会TLE了。

  我们可以发现总花费为  

  序列除了被减少外,未被覆盖之内。我们可以通过预处理前缀和来优化,达到 O(N).

View Code
#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<algorithm>

using namespace std;

const int mod = 1e9+7;

const int N = 1e5+10;

typedef unsigned long long LL; 

int a[N], n; 

LL s[N];



int main(){ 

    int T;

    scanf( "%d", &T );

    for( int Case = 1; Case <= T; Case++ ){

        scanf("%d", &n);  

        for(int i = 1; i <= n; i++) scanf("%d", &a[i] ); 

         sort( a+1, a+n+1 ); 

         s[0] = 0; a[0] = 1;

         for(int i = 1; i <= n; i++) s[i] = s[i-1]+a[i];

        LL res = 0;

        for(int i = 1; i <= n-1; i++){

            LL A = a[i]-a[i-1]+1 ;   //printf("A = %I64d\n", A);

            if( A > 0 ){ 

                if( A == 1 ) res = (res+(n-i))%mod;

                else { 

                    int tot = n-i;  

                    LL tmp_sum = (s[n]-s[i]) - 1LL*tot*(a[i-1]-1);  

                    LL tmp = (1LL*tot*A*(A+1)/2)%mod + (1LL*(tmp_sum-tot*(A-1))*(A-1)%mod+(1LL*tot*A*(A-1)/2)%mod )*tot%mod;   

                    res = (res+tmp+mod)%mod; 

                }

            }        

        }

        printf("Case %d: %I64d\n", Case, res );        

    }

    return 0;    

}

 

你可能感兴趣的:(JOIN)