• 【FFT(母函数)+容斥】BZOJ3771-Triple


    【题目大意】

    给出 n个物品,价值为别为Xi且各不相同,现在可以取1个、2个或3个,问每种价值和有几种情况?

    *顺序不同算一种

    【思路】

    显然是个母函数,A表示每种物品取一个的情况,B表示每种物品取二个的情况,C表示每种物品取三个的情况。用指数表示价值,系数表示该价值的个数,显然多项式相乘后指数会相加,系数会相乘,很容易就求出来了。

    所以对于每种物品价值Xi,A[xi]++,B[2*xi]++,C[3*xi]++。

    如果取1个物品,答案就是A。

    如果取2个物品,A^2中有重复的(xi,xi)的情况,所以答案为A^2-B。

    如果去3个物品,A^3中可能有(xi,xi,xi)(xi,xi,yi)(xi,yi,xi)(yi,xi,xi)这几种重复的情况,而A*B能够求出所有形容(xi,xi,xi)和(xi,yi,yi)的情况数。(xi,xi,yi)(xi,yi,xi)(yi,xi,xi)总的情况数=(xi,yi,yi)*3,而A*B*3又会多减去了两次(xi,xi,xi),所以要用C加回来。所以答案为A^3-3*B*A+2C。又由于顺序不同算一种情况,因为每种物品价值都不一样,情况(2)/2,情况(3)/6。

    故总情况数量=++

     (公式好烦啊把默认编辑器换成Markdown算了)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<complex>
     6 #include<cmath>
     7 #define pi acos(-1)
     8 using namespace std;
     9 typedef complex<double> com;
    10 typedef long long ll;
    11 const int MAXN=262144+50;
    12 com a[MAXN],b[MAXN],c[MAXN];
    13 int m,n,len,L,Rev[MAXN];
    14 void get_bit(){for (n=1,L=0;n<m;n<<=1) L++;} 
    15 void get_Rtable(){for (int i=0;i<n;i++) Rev[i]=(Rev[i>>1]>>1)|((i&1)<<(L-1));}
    16 
    17 void FFT(com* a,int flag)
    18 {
    19     for (int i=0;i<n;i++)if(i<Rev[i])swap(a[i],a[Rev[i]]); //利用逆序表,快速求逆序
    20     for (int i=1;i<n;i<<=1)
    21     {
    22         com wn(cos(2*pi/(i*2)),flag*sin(2*pi/(i*2)));
    23         for (int j=0;j<n;j+=(i<<1))
    24         {
    25             com w(1,0);
    26             for (int k=0;k<i;k++,w*=wn)
    27             {
    28                 com x=a[j+k],y=w*a[j+k+i];
    29                 a[j+k]=x+y;
    30                 a[j+k+i]=x-y;
    31             }
    32         }
    33     }
    34     if (flag==-1) for (int i=0;i<n;i++) a[i]/=n;
    35 }
    36 
    37 
    38 void init()
    39 {
    40     scanf("%d",&n);
    41     for (int i=0;i<n;i++)
    42     {
    43         int ai;
    44         scanf("%d",&ai);
    45         a[ai]+=(1);b[2*ai]+=(1);c[3*ai]+=(1);
    46         len=max(len,3*ai);
    47     }
    48 }
    49 
    50 void solve()
    51 {
    52     m=len<<1;
    53     len++;m++;
    54     get_bit();
    55     get_Rtable();
    56     FFT(a,1);
    57     FFT(b,1);
    58     FFT(c,1);
    59     com t2=(2),t3=(3),t6=(6);
    60     for (int i=0;i<n;i++) 
    61        a[i]=(a[i]*a[i]*a[i]-t3*a[i]*b[i]+t2*c[i])/t6+(a[i]*a[i]-b[i])/t2+a[i];
    62     FFT(a,-1);
    63 }
    64 
    65 void get_ans()
    66 {
    67     for (int i=1;i<m;i++) 
    68     {
    69         ll num=(ll)(a[i].real()+0.5);
    70         if (num!=0) printf("%d %d
    ",i,num);
    71     }
    72 }
    73 
    74 int main()
    75 {
    76     init();
    77     solve();
    78     get_ans();
    79     return 0;
    80 }
  • 相关阅读:
    剑指offer-最小的k个数
    剑指offer-数组中出现次数超过一半的数字
    android开发------响应用户事件
    android开发------初识Activity
    android开发------编写用户界面之相对布局
    android开发------编写用户界面之线性布局(补充知识)
    android开发------编写用户界面之线性布局
    android开发------第一个android程序
    加密狗的工作原理
    克隆加密狗、复制加密狗、破解加密狗的定义区别
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5717520.html
Copyright © 2020-2023  润新知