[BZOJ3771]Triple

Triple

Subject to the effect

To give you a bunch of valuable items, you can choose one of them, two or three, the election can not be repeated, can seek elected and the total value of the program number.

Solution

FFT + inclusion-exclusion

Coefficients of a polynomial is the program number, the index value is, here a polynomial \ (A [x] \) represents the x power of polynomial A

Then we multiply the two polynomials, you can get one element selected side, the other side also selected a number of elements add up program

Principle: polynomial multiplication, multiplied by two, adding the index, multiplied by the coefficient, the equivalent of adding value, multiplied by the number of programs

So we have established three polynomials, respectively deposit a selected certain items, the value of the number of two, three

Set a, b, c, the article when a value of X, \ (A [X] ++ \) , \ (B [X + X] ++ \) , \ (C [X + X + X ] + \)

Then for each value of i, divided three categories:

1, only a selected, then the answer is obviously \ (a [i] \)

2, selected from the two, then the answer is not heavy \ (A [I] ^ 2 \) , but where there will be two different cases, and then remove the sequence, the final answer is \ ((a [i] ^ 2-b [i]) \ over 2 \)

3, three election at this time is not re-answer \ (A [I] ^ 3 \) , remove (x, x, x) and (x, y, y), (y, x, y), ( where y, y, x), we must subtract \ (a [I] \ Times B [I] \. 3 Times \) , but so many minus two (x, x, x), so to add back \ (c [i] \ times 2 \)

The final answer is \ ((a [i] ^ 3- (a [i] \ times b [i] \ times 3) + (c [i] \ times 2)) \ over 6 \)

code:

#include<bits/stdc++.h>
using namespace std;
struct comp{
    double x,y;
    comp (double xx=0,double yy=0){
        x=xx,y=yy;
    }
}a[200010],b[200010],c[200010],ans[200010];
comp operator +(comp a,comp b){return comp(a.x+b.x,a.y+b.y);}
comp operator -(comp a,comp b){return comp(a.x-b.x,a.y-b.y);}
comp operator *(comp a,comp b){return comp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
comp operator *(comp a,double b){return comp(a.x*b,a.y*b);}
int rev[200010];
int lim=1;
const double pi=acos(-1);
void fft(comp *A,int type){
    for(int i=0;i<lim;++i){
        if(i<rev[i])swap(A[i],A[rev[i]]);
    }
    for(int mid=1;mid<lim;mid<<=1){
        comp wn=comp(cos(pi/mid),type*sin(pi/mid));
        for(int j=0,R=mid<<1;j<lim;j+=R){
            comp w=comp(1,0);
            for(int k=0;k<mid;++k,w=w*wn){
                comp x=A[j+k],y=w*A[j+k+mid];
                A[j+k]=x+y;
                A[j+k+mid]=x-y;
            }
        }
    }
    if(type==-1){
        for(int i=0;i<lim;++i)A[i].x/=lim;
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int len=0;
    for(int i=1;i<=n;++i){
        int x;
        scanf("%d",&x);
        a[x].x+=1.0,b[x*2].x+=1.0,c[x*3].x+=1.0;
        len=max(len,x*3);
    }
    int tmp=0;
    while(lim<=len){
        lim<<=1,tmp++;
    }
    //cout<<lim<<" "<<tmp<<endl;
    for(int i=0;i<=lim;++i){
        rev[i]=rev[i>>1]>>1|(i&1)<<(tmp-1);
    }
    fft(a,1);
    fft(b,1);
    fft(c,1);
    for(int i=0;i<lim;++i){
        ans[i]=a[i];
        ans[i]=ans[i]+(a[i]*a[i]-b[i])*0.5;
        ans[i]=ans[i]+(a[i]*a[i]*a[i]-b[i]*a[i]*3.0+c[i]*2.0)*(1.0/6.0);
    }
    fft(ans,-1);
    for(int i=0;i<lim;++i){
        int num=ans[i].x+0.5;
        if(num){
            printf("%d %d\n",i,num);
        }
    }
}

Guess you like

Origin www.cnblogs.com/youddjxd/p/11613122.html