C -- Coloring Game
思路:不难看出,当 Alice 选完三个数 a b c(其中 a ≤ b ≤ c)后,Bob 能选的只有两种情况:
- 选择 c,这样只用比较 a+b 和 c 的大小关系,其中 a+b 一定要大于c;
- 选择数组最大值 a[n],这样只用比较 a+b+c 和 a[n] 的大小关系,且前者要更大。
所以,排序后枚举外层 a_id 和内层 b_id:
- 对于情况1:因为 a+b 的和一开始较小,后续逐渐变大,所以最大能选择的 c_id 一开始会较小,然后会随着 b_id 的变大而变大,该情况的"最大满足当前条件的 c_id"记为 k;
- 对于情况2:因为 a+b 的和一开始较小,需要较大的 c 才能使得 a+b+c > a[n],因此满足条件的最小 c_id 一开始会较大,后续随着 a+b 的增大而变小,该情况的"最小满足当前条件的 c_id"记为 l。
那么,对于每对 (a_id, b_id),可选的 c_id 数量即为 [l, k] 区间长度。利用 k、l 单调移动的特点,可用双指针在 O(n²) 内完成。
view code
cpp
#include<bits/stdc++.h>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define endl '\n'
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0; rep(i,1,n+1) res=(res+k)%i; return (res+s)%n;}
inline ll read(){ ll f=1,x=0; char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } return x*f; }
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
ll a[maxn];
void sol() {
ll n = read();
rep(i,1,n) a[i] = read();
sort(a+1,a+1+n);
ll ans = 0;
rep(i,1,n) {
ll k = i+2, l = n;
rep(j,i+1,n-1) {
while(k <= n && a[i] + a[j] > a[k]) k++;
while(l > j && a[i] + a[j] + a[l] > a[n]) l--;
ll k1 = min(n, k-1), l1 = max(l+1, j+1);
if(k1 >= l1) ans += (k1 - l1 + 1);
}
}
cout << ans << endl;
}
int main() {
int kase;
cin >> kase;
while(kase--) sol();
return 0;
}