[BZOJ 3771] Triple (FFT + generating function)
Face questions
Given the n items, not for the value of \ (w_i \) and not the same, you can now take one, two, or three, ask each value and there are several circumstances?
analysis
Such problems readily occur to generate a counting function.
Set generation function \ (A (X) = \ sum_. 1 = {I} n-X} ^ {^ W_i} {\) , index value, the number of coefficients selected program. Each article A represents an access scheme. Similarly, we can write for each item 2 and 3 taken generating function.
\(B(x)=\sum_{i=1}^{n} x^{2w_i}\)
\(C(x)=\sum_{i=1}^{n} x^{3w_i}\)
Then began vigorously inclusion and exclusion.
Take the case of three different items
Direct access to the program number 3 is the article \ (A ^. 3 (X) \) , but we need to subtract repeated as \ ((a, a, b ), (a, b, a) \) even the same kind of situation. Selected from two articles \ (A \) solution for \ (B (X) \) , then select an item \ (B \) solution for \ (A (X) \) , any arrangement of three kinds. Therefore, to reduce \ (3A (x) B ( x) \)
However, each item takes 3 \ ((a, a, a ) \) This program will be minus 3 times, but in fact only need to subtract one time, so also add back \ (2C (x) \ )
Noting \ ((a, b, c ) \) six different permutation scheme counted only once. Total answers
\[\frac{A^3(x)-3A(x)B(x)+2C(x)}{6}\]
Take a case where two different items
Direct access to the article 3 scheme \ (A ^ 2 (X) \) . Duplicate \ ((a, a) \ ) in this case is a program \ (B (X) \) , and \ ((a, b) \ ) 2 permutations calculated only once. Total answers
\[\frac{A^2(x)-B(x))}{2}\]
Take a different embodiment of the article
It is simply \ (A (x) \)
In summary, the answer is always
\[\frac{A^3(x)-3A(x)B(x)+2C(x)}{6}+\frac{A^2(x)-B(x))}{2}+A(x)\]
First A, B, C switch to a point FFT is then multiplied by the value of the expression, and then click on the inverse transform answer.
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 400000
using namespace std;
typedef long long ll;
const double pi=acos(-1.0);
struct com{
double real;
double imag;
com(){
}
com(double _real,double _imag){
real=_real;
imag=_imag;
}
com(double x){
real=x;
imag=0;
}
void operator = (const com x){
this->real=x.real;
this->imag=x.imag;
}
void operator = (const double x){
this->real=x;
this->imag=0;
}
friend com operator + (com p,com q){
return com(p.real+q.real,p.imag+q.imag);
}
friend com operator + (com p,double q){
return com(p.real+q,p.imag);
}
friend com operator - (com p,com q){
return com(p.real-q.real,p.imag-q.imag);
}
friend com operator - (com p,double q){
return com(p.real-q,p.imag);
}
friend com operator * (com p,com q){
return com(p.real*q.real-p.imag*q.imag,p.real*q.imag+p.imag*q.real);
}
friend com operator * (com p,double q){
return com(p.real*q,p.imag*q);
}
friend com operator / (com p,double q){
return com(p.real/q,p.imag/q);
}
void print(){
printf("%lf + %lf i ",real,imag);
}
};
void fft(com *x,int n,int type){
static int rev[maxn+5];
int tn=1,k=0;
while(tn<n){
k++;
tn*=2;
}
for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
for(int i=0;i<n;i++) if(i<rev[i]) swap(x[i],x[rev[i]]);
for(int len=1;len<n;len*=2){
int sz=len*2;
com wn1=com(cos(2*pi/sz),type*sin(2*pi/sz));
for(int l=0;l<n;l+=sz){
int r=l+len-1;
com wnk=1;
for(int i=l;i<=r;i++){
com tmp=x[i+len];
x[i+len]=x[i]-wnk*tmp;
x[i]=x[i]+wnk*tmp;
wnk=wnk*wn1;
}
}
}
if(type==-1){
for(int i=0;i<n;i++) x[i].real/=n;
}
}
void mul(com *a,com *b,com *ans,int n){
// fft(a,n,1);
// fft(b,n,1);
//避免多次fft
for(int i=0;i<n;i++) ans[i]=a[i]*b[i];
fft(ans,n,-1);
}
int n;
int val[maxn+5];
com a[maxn+5],b[maxn+5],c[maxn+5];
com ans[maxn+5];
int main(){
scanf("%d",&n);
int mv=0;
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
a[val[i]]=a[val[i]]+1;
b[val[i]*2]=b[val[i]*2]+1;
c[val[i]*3]=c[val[i]*3]+1;
mv=max(mv,val[i]);
}
int tn=1,k=0;
while(tn<mv*3){
k++;
tn*=2;
}
fft(a,tn,1);
fft(b,tn,1);
fft(c,tn,1);
for(int i=0;i<tn;i++){
ans[i]=(a[i]*a[i]*a[i]-3*a[i]*b[i]+2*c[i])/6+(a[i]*a[i]-b[i])/2+a[i];
}
fft(ans,tn,-1);
for(int i=0;i<=mv*3;i++){
if(ll(ans[i].real+0.5)){
printf("%d %lld\n",i,ll(ans[i].real+0.5));
}
}
}