题目描述: 点击这里
思路:
- 对于 30 % p t s ( n ≤ 200 ) , 30\%pts(n≤200), 30%pts(n≤200), 暴力枚举即可,时间复杂度 O ( n 3 ) O(n^3) O(n3)。
- 对于另外 20 % p t s ( 20\%pts( 20%pts(木棍长度全部相等 ) , ), ), 考虑用数学思想,即 C n 3 C^3_{n} Cn3。
- 正解: 1. 利用桶排序,将每个数出现的次数统计出来。2.进行分段讨论,在它前面的所有数一组,后面的所有数一组,它自己一组,分别累计和,并且用前缀和优化。
代码:
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
template < typename T > void read(T &x)
{
int f = 1;x = 0;char c = getchar();
for (;!isdigit(c);c = getchar()) if (c == '-') f = -f;
for (; isdigit(c);c = getchar()) x = x * 10 + c - '0';
x *= f;
}
const long long mod = 998244353;
int a[200005];
long long bin[200005];
long long sum[200005];
int main()
{
//freopen(".in", "r", stdin);
//freopen(".out", "w", stdout);
int n, binmax = INT_MIN;
long long ans = 0;
read(n);
for(int i = 1;i <= n;i++)
{
read(a[i]);
bin[a[i]]++;
binmax = max(binmax, a[i]);
}
int t = a[1];
int flag = 1;
for(int i = 2;i <= n;i++)
if(a[i] != t)
{
flag = 0;
break;
}
if(flag)
{
long long ans = 1;
for(int i = n;i > n - 3;i--)
{
ans *= i;
}
cout << (ans / 6) % mod << endl;
return 0;
}
if(n <= 200)
{
for(int i = 1;i <= n;i++)
for(int j = i + 1;j <= n;j++)
for(int k = j + 1;k <= n;k++)
if((a[i] == a[j] || a[i] == a[k] || a[j] == a[k]) && (a[i] + a[j] > a[k]) && a[i] + a[k] > a[j] && a[j] + a[k] > a[i])
ans++;
cout << ans % mod << endl;
return 0;
}
sum[0] = 0;
for(int i = 1;i <= binmax;i++)
sum[i] = bin[i] + sum[i - 1];
long long front = 0;
for(int i = 1;i <= binmax;++i)
if(bin[i])
{
if(bin[i] >= 3)
{
long long ansj = 1;
for(int j = bin[i];j > bin[i] - 3;--j)
ansj *= j;
ans += ansj / 6;
ans %= mod;
}
if(bin[i] >= 2)
{
long long tx = bin[i] * (bin[i] - 1) / 2;
ans += front * tx;
ans %= mod;
long long up = min(i * 2, binmax + 1) - 1;
long long ty = sum[up] - sum[i];
ans += ty * tx;
ans %= mod;
}
front += bin[i];
}
cout << ans << endl;
return 0;
}