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; }