题目大意:
给你三个数组表示三角形三边的取值情况,问你最多能构成多少个三角形。
数据范围:
T
<
=
100
,
n
<
=
1
0
5
,
A
i
<
=
1
0
5
T<=100,n<=10^5,A_i<=10^5
T<=100,n<=105,Ai<=105
思路:
如果正面去考虑的话,需要处理很多的情况,所以显然从反面来考虑问题会更为简单,即去掉三个不能构成三角形的情况。
因为数据保证只有不超过20组超过1000的数据,所以对1000以下的直接暴力显然更快,用fft处理大数据会更加便利。
当时比赛的时候,没有fft板子,结果在IDFT时候忘记修正。。。
#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
using namespace std;
typedef long long ll;
const int maxn = 111111 , maxl = 262144 + 10;
struct cp{
double x,y;
cp(double _x = 0.0,double _y =0.0){
x = _x;y =_y;
}
cp operator - (const cp &b)const{
return cp(x-b.x,y-b.y);
}
cp operator + (const cp &b)const{
return cp(x+b.x,y+b.y);
}
cp operator * (const cp &b)const{
return cp(x*b.x - y*b.y,x*b.y + y*b.x);
}
}g[maxl] , fa[maxl] , fb[maxl] , fc[maxl] , w[maxl];
const double pi = acos(-1.0);
int rev[maxl] , n;
void fft(cp *a,int n,int inv)
{
int bit=0;
while ((1<<bit)<n)bit++;
rep(i,0,n-1)
{
rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
if (i<rev[i])swap(a[i],a[rev[i]]);
}
for (int mid=1;mid<n;mid*=2)//mid是准备合并序列的长度的二分之一
{
cp temp(cos(pi/mid),inv*sin(pi/mid));//单位根,pi的系数2已经约掉了
for (int i=0;i<n;i+=mid*2)//mid*2是准备合并序列的长度,i是合并到了哪一位
{
cp omega(1,0);
for (int j=0;j<mid;j++,omega=omega*temp)//只扫左半部分,得到右半部分的答案
{
cp x=a[i+j],y=omega*a[i+j+mid];
a[i+j]=x+y,a[i+j+mid]=x-y;//这个就是蝴蝶变换什么的
}
}
}
if(inv==-1) rep(i,0,n-1) a[i].x/=n;
}
int T , L;
typedef long long ll;
ll ans , a[maxl] , b[maxl] , c[maxl];
void work( cp *a , cp *b , ll *c ){
for( int i = 0 ; i < L ; ++i ) g[i] = a[i] * b[i];
fft( g , L , -1 );
ll sum = 0;
for( int i = 0 ; i <= 100000 ; i++ ){
ans -= sum * c[i];
sum += (ll)(g[i].x + 0.5);
}
}
inline int read() {
int x = 0;
bool f = 0;
char ch = getchar();
while (ch < '0' || '9' < ch)
f |= ch == '-', ch = getchar();
while ('0' <= ch && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return f ? -x : x;
}
namespace bl{
int a[1111] , b[1111] , c[1111] , sa[200005] , sb[200005] , sc[200005];
void work(){
memset( sa , 0 , sizeof sa );
memset( sb , 0 , sizeof sb );
memset( sc , 0 , sizeof sc );
for( int i = 1 ; i <= n ; ++i ) a[i] = read();
for( int i = 1 ; i <= n ; ++i ) b[i] = read();
for( int i = 1 ; i <= n ; ++i ) c[i] = read();
for( int i = 1 ; i <= n ; ++i )
for( int j = 1 ; j <= n ; ++j ){
sc[a[i] + b[j]]++;
sb[a[i] + c[j]]++;
sa[b[i] + c[j]]++;
}
for( int i = 1 ; i <= 100000 ; ++i )
sa[i] += sa[i - 1] , sb[i] += sb[i - 1] , sc[i] += sc[i - 1];
for( int i = 1 ; i <= n ; ++i ) ans -= sa[a[i] - 1] + sb[b[i] - 1] + sc[c[i] - 1];
}
}
int main(){
T = read(); L = 1 << 18;
for( int cas = 1 ; cas <= T ; ++cas ){
n = read() , ans = (ll)n * n * n;
memset( a , 0 , sizeof a );
memset( b , 0 , sizeof b );
memset( c , 0 , sizeof c );
if( n <= 1000 ){
bl::work();
printf("Case #%d: %lld\n" , cas , ans );
continue;
}
for( int i = 1 ; i <= n ; ++i ){
a[read()]++;
}
for( int i = 1 ; i <= n ; ++i ){
b[read()]++;
}
for( int i = 1 ; i <= n ; ++i ){
c[read()]++;
}
for( int i = 0 ; i < L ; ++i ){
fa[i] = cp(a[i] , 0);
fb[i] = cp(b[i] , 0);
fc[i] = cp(c[i] , 0);
}
fft(fa , L , 1);
fft(fb , L , 1);
fft(fc , L , 1);
work(fa , fb , c);
work(fb , fc , a);
work(fa , fc , b);
printf("Case #%d: %lld\n" , cas , ans );
}
return 0;
}