• 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 }
  • 相关阅读:
    个推技术实践 | 掌握这两个调优技巧,让你的TiDB性能提速千倍!
    3·8节,带你走进程序媛小姐姐的一天.mp4
    c++ fstream读写方式
    c++ ignore
    AI 智能写情诗、藏头诗
    随机数生成
    R script 入门教程
    Error: Cannot find module '@vue/clipluginbabel'
    Please, upgrade your dependencies to the actual version of corejs.
    java获取不到真实ip;获取不到ip地址;
  • 原文地址:https://www.cnblogs.com/qldabiaoge/p/10431947.html
Copyright © 2020-2023  润新知