• 【bzoj3771】Triple FFT+容斥原理


    题目描述

    樵夫的每一把斧头都有一个价值,不同斧头的价值不同。总损失就是丢掉的斧头价值和。
    他想对于每个可能的总损失,计算有几种可能的方案。
    注意:如果水神拿走了两把斧头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


    题解

    FFT+容斥原理

    一个数的方案数$f(x)$,就是原序列的生成函数(初学时理解为桶 = =)。

    两个数的方案数为$(f*f)(x)$,但其中包含了两次使用了同一个数的方案数$g(x)=f(2x)$,而其余的方案统计了两次,所以方案数为$frac 12(f*f-g)(x)$。

    三个数的方案数为$(f*f*f)(x)$,但其中包含了三次使用了同一个数的方案数$h(x)=f(3x)$,包含了使用了两次同一个数,另一个数不同的方案数$(f*g-h)(x)*3$(里面减掉$h$是因为三次使用同一个数的方案数被重复计算,而乘3是因为在$(f*f*f)(x)$中计算了3次),而其余的方案统计了,所以方案数为$frac 16((f*f*f-3*f*g+2*h)(x))$。

    最后数值不为0的就是答案。

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #define N 1 << 19
    #define pi acos(-1)
    using namespace std;
    typedef long long ll;
    struct data
    {
    	double x , y;
    	data() {x = y = 0;}
    	data(double x0 , double y0) {x = x0 , y = y0;}
    	data operator+(const data a)const {return data(x + a.x , y + a.y);}
    	data operator-(const data a)const {return data(x - a.x , y - a.y);}
    	data operator*(const data a)const {return data(x * a.x - y * a.y , x * a.y + y * a.x);}
    }a[N] , b[N] , c[N] , d[N] , e[N];
    int f[N];
    void fft(data *a , int n , int flag)
    {
    	int i , j , k;
    	for(i = k = 0 ; i < n ; i ++ )
    	{
    		if(i > k) swap(a[i] , a[k]);
    		for(j = (n >> 1) ; (k ^= j) < j ; j >>= 1);
    	}
    	for(k = 2 ; k <= n ; k <<= 1)
    	{
    		data wn(cos(2 * pi * flag / k) , sin(2 * pi * flag / k));
    		for(i = 0 ; i < n ; i += k)
    		{
    			data t , w(1 , 0);
    			for(j = i ; j < i + (k >> 1) ; j ++ , w = w * wn)
    				t = w * a[j + (k >> 1)] , a[j + (k >> 1)] = a[j] - t , a[j] = a[j] + t;
    		}
    	}
    	if(flag == -1)
    		for(i = 0 ; i < n ; i ++ )
    			a[i].x /= n;
    }
    int main()
    {
    	int n , i , t , m = 0 , len;
    	scanf("%d" , &n);
    	while(n -- ) scanf("%d" , &t) , a[t].x ++ , b[t * 2].x ++ , c[t * 3].x ++ , d[t].x ++ , e[t * 2].x ++ , f[t] ++ ;
    	m = t * 3;
    	for(len = 1 ; len < m ; len <<= 1);
    	fft(a , len , 1) , fft(b , len ,  1);
    	for(i = 0 ; i < len ; i ++ ) b[i] = b[i] * a[i] , a[i] = a[i] * a[i] * a[i];
    	fft(a , len , -1) , fft(b , len , -1);
    	fft(d , len , 1);
    	for(i = 0 ; i < len ; i ++ ) d[i] = d[i] * d[i];
    	fft(d , len , -1);
    	for(i = 1 ; i <= m ; i ++ )
    		if((ll)(a[i].x - 3 * b[i].x + 2 * c[i].x + 0.5) / 6 + (ll)(d[i].x - e[i].x + 0.5) / 2 + f[i])
    			printf("%d %lld
    " , i , (ll)(a[i].x - 3 * b[i].x + 2 * c[i].x + 0.5) / 6 + (ll)(d[i].x - e[i].x + 0.5) / 2 + f[i]);
    	return 0;
    }
    

     

  • 相关阅读:
    文件下载
    字符串截取
    GAMES101 作业1
    GAMES101 作业0
    常见的企业管理系统有哪些
    Spring---AoP(面向切面编程)原理学习笔记【全】
    什么是OOP(Object Oriented Programming)面向对象编程
    Spring框架之控制反转IoC(Inversion of Control)的理解
    Typora编辑器MarkDown语法
    国民经济行业分类与代码(GB/T 4754-2017、GB/T 4754-2011、GB/T 4754-2002)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7413487.html
Copyright © 2020-2023  润新知