zoukankan      html  css  js  c++  java
  • BZOJ 3771 母函数裸题

    题目描述

    我们讲一个悲伤的故事。
    从前有一个贫穷的樵夫在河边砍柴。
    这时候河里出现了一个水神,夺过了他的斧头,说:
    “这把斧头,是不是你的?”
    樵夫一看:“是啊是啊!”
    水神把斧头扔在一边,又拿起一个东西问:
    “这把斧头,是不是你的?”
    樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!”
    水神又把手上的东西扔在一边,拿起第三个东西问:
    “这把斧头,是不是你的?”
    樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了。
    于是他又一次答:“是啊是啊!真的是!”
    水神看着他,哈哈大笑道:
    “你看看你现在的样子,真是丑陋!”
    之后就消失了。
     
    樵夫觉得很坑爹,他今天不仅没有砍到柴,还丢了一把斧头给那个水神。
    于是他准备回家换一把斧头。
    回家之后他才发现真正坑爹的事情才刚开始。
    水神拿着的的确是他的斧头。
    但是不一定是他拿出去的那把,还有可能是水神不知道怎么偷偷从他家里拿走的。
    换句话说,水神可能拿走了他的一把,两把或者三把斧头。
     
    樵夫觉得今天真是倒霉透了,但不管怎么样日子还得过。
    他想统计他的损失。
    樵夫的每一把斧头都有一个价值,不同斧头的价值不同。总损失就是丢掉的斧头价值和。
    他想对于每个可能的总损失,计算有几种可能的方案。
    注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视为一种方案。拿走三把斧头时,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。
     

    输入格式

    第一行是整数N,表示有N把斧头。
    接下来n行升序输入N个数字Ai,表示每把斧头的价值。
     

    输出格式

    若干行,按升序对于所有可能的总损失输出一行x y,x为损失值,y为方案数。
     

    样例输入

    4
    4
    5
    6
    7
    

    样例输出

    4 1
    5 1
    6 1
    7 1
    9 1
    10 1
    11 2
    12 1
    13 1
    15 1
    16 1
    17 1
    18 1
    样例解释
    11有两种方案是4+7和5+6,其他损失值都有唯一方案,例如4=4,5=5,10=4+6,18=5+6+7.

    提示

    所有数据满足:Ai<=40000

    题意: 从n个物品中选取1个或 2个 或 3个 的价值和是多少 对于一个价值 输出方案数 (方案无顺序要求) 

    简单讲一下母函数 例如有3个物品  他们的价值是1,2,3 

    构造一个母函数 f(x) = x^1 + x^2 + x^3 (表示取一件)  

    下面我来解释一下这个f(x) 指数为物品的价值 每一项前面的系数表示方案数 

      x^1  表示取一件物品取到价值为 1 的方案数为 1 

     x^2  表示取一件物品取到价值为 2 的方案数为 1 以此类推 

     g(x)= x^2 + x^4 + x^6 (表示同一件物品取两次)

     z(x)= x^3 + x^6 + x^9 (表示同一件物品取三次)

    那么取两次而且方案数不重复的结果是   ( f ( x ) * f ( x ) - g ( x ) ) / 2  (f ( x ) * f ( x ) 会多算了一次取两个相同的方案 所以要减去 )

    取三次的方案就是  ( f ( x ) * f ( x ) * f(x)-3 * f ( x ) * g(x) +2 * z(x)  )/6 

    (无顺序要求所以要除以一个3的全排列  f (x) * g (x) / 2  多算了的取了两个相同的方案数 因为下面有一个6的分母 所以乘以了一个系数 3

    但是这里面还包括了选取了3个都相同的方案  所以要加上 2*z(x))

    这里面的多项式的计算就直接通过FFT优化就好了  (FFT板子当作黑盒直接使用就行了)

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <queue>
      4 #include <cmath>
      5 #include <algorithm>
      6 #include <set>
      7 #include <iostream>
      8 #include <map>
      9 #include <stack>
     10 #include <string>
     11 #include <vector>
     12 #define  pi acos(-1.0)
     13 #define  eps 1e-9
     14 #define  fi first
     15 #define  se second
     16 #define  rtl   rt<<1
     17 #define  rtr   rt<<1|1
     18 #define  bug         printf("******
    ")
     19 #define  mem(a,b)    memset(a,b,sizeof(a))
     20 #define  name2str(x) #x
     21 #define  fuck(x)     cout<<#x" = "<<x<<endl
     22 #define  f(a)        a*a
     23 #define  sf(n)       scanf("%d", &n)
     24 #define  sff(a,b)    scanf("%d %d", &a, &b)
     25 #define  sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
     26 #define  sffff(a,b,c,d) scanf("%d %d %d %d", &a, &b, &c, &d)
     27 #define  pf          printf
     28 #define  FRE(i,a,b)  for(i = a; i <= b; i++)
     29 #define  FREE(i,a,b) for(i = a; i >= b; i--)
     30 #define  FRL(i,a,b)  for(i = a; i < b; i++)+
     31 #define  FRLL(i,a,b) for(i = a; i > b; i--)
     32 #define  FIN         freopen("data.txt","r",stdin)
     33 #define  gcd(a,b)    __gcd(a,b)
     34 #define  lowbit(x)   x&-x
     35 #define rep(i,a,b) for(int i=a;i<b;++i)
     36 #define per(i,a,b) for(int i=a-1;i>=b;--i)
     37 using namespace std;
     38 typedef long long  LL;
     39 typedef unsigned long long ULL;
     40 const int maxn = 3e5 + 7;
     41 const int maxm = maxn * 4;
     42 int n, m, a[maxn], b[maxn];
     43 int len, res[maxm], mx; //开大4倍
     44 struct cpx {
     45     double r, i;
     46     cpx ( double r = 0, double i = 0 ) : r ( r ), i ( i ) {};
     47     cpx operator+ ( const cpx &b ) {
     48         return cpx ( r + b.r, i + b.i );
     49     }
     50     cpx operator- ( const cpx &b ) {
     51         return cpx ( r - b.r, i - b.i );
     52     }
     53     cpx operator* ( const cpx &b ) {
     54         return cpx ( r * b.r - i * b.i, i * b.r + r * b.i );
     55     }
     56 } va[maxm], vb[maxm];
     57 void rader ( cpx F[], int len ) { //len = 2^M,reverse F[i] with  F[j] j为i二进制反转
     58     int j = len >> 1;
     59     for ( int i = 1; i < len - 1; ++i ) {
     60         if ( i < j ) swap ( F[i], F[j] ); // reverse
     61         int k = len >> 1;
     62         while ( j >= k ) j -= k, k >>= 1;
     63         if ( j < k ) j += k;
     64     }
     65 }
     66 void FFT ( cpx F[], int len, int t ) {
     67     rader ( F, len );
     68     for ( int h = 2; h <= len; h <<= 1 ) {
     69         cpx wn ( cos ( -t * 2 * pi / h ), sin ( -t * 2 * pi / h ) );
     70         for ( int j = 0; j < len; j += h ) {
     71             cpx E ( 1, 0 ); //旋转因子
     72             for ( int k = j; k < j + h / 2; ++k ) {
     73                 cpx u = F[k];
     74                 cpx v = E * F[k + h / 2];
     75                 F[k] = u + v;
     76                 F[k + h / 2] = u - v;
     77                 E = E * wn;
     78             }
     79         }
     80     }
     81     if ( t == -1 ) //IDFT
     82         for ( int i = 0; i < len; ++i ) F[i].r /= len;
     83 }
     84 void Conv ( cpx a[], cpx b[], int len ) { //求卷积
     85     FFT ( a, len, 1 );
     86     FFT ( b, len, 1 );
     87     for ( int i = 0; i < len; ++i ) a[i] = a[i] * b[i];
     88     FFT ( a, len, -1 );
     89 }
     90 void gao () {
     91     len = 1;
     92     mx = n + m;
     93     while ( len <= mx ) len <<= 1; //mx为卷积后最大下标
     94     for ( int i = 0; i < len; i++ ) va[i].r = va[i].i = vb[i].r = vb[i].i = 0;
     95     for ( int i = 0; i < n; i++ ) va[i].r = a[i]; //根据题目要求改写
     96     for ( int i = 0; i < m; i++ ) vb[i].r = b[i]; //根据题目要求改写
     97     Conv ( va, vb, len );
     98     for ( int i = 0; i < len; ++i ) res[i] += va[i].r + 0.5;
     99 }
    100 int B[maxn], C[maxn], ans[maxm], cnt1[maxm], cnt2[maxm];
    101 int main() {
    102     FIN;
    103     sf ( n );
    104     int maxxA = -1;
    105     for ( int i = 0, x; i < n ; i++ ) {
    106         sf ( x );
    107         a[x]++, b[x]++, ans[x]++;
    108         maxxA = max ( maxxA, x );
    109         B[2 * x]++, C[3 * x]++;
    110     }
    111     n = m = ++maxxA;
    112     gao();
    113     for ( int i = 0 ; i <= 2 * maxxA ; i++ ) ans[i] += ( res[i] - B[i] ) / 2, b[i] = res[i], res[i] = 0;
    114     m = 2 * maxxA;
    115     gao();
    116     for ( int i = 0 ; i <= 3 * maxxA ; i++ ) cnt1[i] = res[i], res[i] = 0;
    117     for ( int i = 0 ; i <= 2 * maxxA ; i++ ) b[i] = B[i];
    118     gao();
    119     for ( int i = 0 ; i <= 3 * maxxA ; i++ ) cnt2[i] = res[i];
    120     for ( int i = 0 ; i <= 3 * maxxA ; i++ ) ans[i] += ( cnt1[i] - 3 * cnt2[i] + 2 * C[i] ) / 6;
    121     for ( int i = 0 ; i <= 3 * maxxA ; i++ ) if ( ans[i] ) printf ( "%d %d
    ", i, ans[i] );
    122     return 0;
    123 }
  • 相关阅读:
    取得窗口大小和窗口位置兼容所有浏览器的js代码
    一个简单易用的导出Excel类
    如何快速启动chrome插件
    网页表单设计案例
    Ubuntu下的打包解包
    The source file is different from when the module was built. Would you like the debugger to use it anyway?
    FFisher分布
    kalman filter
    Group delay Matlab simulate
    24位位图格式解析
  • 原文地址:https://www.cnblogs.com/qldabiaoge/p/10431947.html
Copyright © 2011-2022 走看看