• BZOJ3771 Triple


    Description

    link

    给定 (n) 种物品,每个有不同的价值,可以取 (1,2,3) 个,求不同的价值和每种价值对应的方案

    (n le 40000)

    Solution

    其实是个计数题,还不是那么好入手的计数题

    定义 (A[i]=[x=i],B[i]=[2 imes x=i],C[i]=[3 imes x=i])

    然后如果取两个进行求价值,那么就是 (A imes A)

    (不是卷积……是直接乘法)

    三个求价值方案就是(A^3)

    显然不对……

    因为每种物品都有重复的,所以要去重……

    所以两种物品的价值方案是 (frac {A^2-B} 2)

    三种就是(frac {A^3-3 imes A imes B +2 imes C} {3!=6})

    额挺显然的容斥,然后就上 (FFT) 做乘法就好了

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	}
    	const int N=15e4+10;
    	struct node{
    		double x,y;
    		node(){}
    		node(double xx,double yy){x=xx; y=yy; return ;}
    		node operator +(const node a){return node(x+a.x,y+a.y);}
    		node operator -(const node a){return node(x-a.x,y-a.y);}
    		node operator *(const node a){return node(x*a.x-y*a.y,y*a.x+x*a.y);}
    		node operator /(const double a){return node(x/a,y/a);}
    		node operator *(const double b){return node(x*b,y*b);}
    	}A[N<<2],B[N<<2],C[N<<2];
    	int n,m,r[N];
    	const double pi=acos(-1);
    	inline void fft(node *f,int n,int opt)
    	{	
    		for(int i=0;i<n;++i) if(i<r[i]) swap(f[i],f[r[i]]);
    		for(int p=2;p<=n;p<<=1)
    		{
    			int len=p>>1; node tmp(cos(pi/len),opt*sin(pi/len));
    			for(int k=0;k<n;k+=p)
    			{
    				node buf(1,0);
    				for(int l=k;l<k+len;++l)
    				{
    					node tt=buf*f[l+len]; 
    					f[len+l]=f[l]-tt; f[l]=f[l]+tt;
    					buf=buf*tmp;
    				}
    			}
    		}
    		if(opt==-1) for(int i=0;i<n;++i) f[i].x/=n;
    		return ;
    	}
    	int maxx,a[N],t;
    	signed main()
    	{
    		t=n=read(); for(int i=1;i<=n;++i) a[i]=read(),A[a[i]].x++,B[a[i]*2].x++,C[a[i]*3].x++;
    		int m=a[n]*3; n=1; while(n<=m) n<<=1;
    		for(int i=0;i<n;++i) r[i]=r[i>>1]>>1|((i&1)?(n>>1):0);
    		
    		fft(A,n,1); fft(B,n,1); fft(C,n,1); 
    		
    		for(int i=0;i<n;++i) A[i]=(A[i]*A[i]*A[i]-A[i]*B[i]*3+C[i]*2)/6+(A[i]*A[i]-B[i])/2+A[i];
    		fft(A,n,-1); for(int i=0;i<=3*a[t];++i) if((int)(A[i].x+0.5)) printf("%lld %lld
    ",i,(int)(A[i].x+0.5));  
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    
  • 相关阅读:
    算法第四章上机实践报告
    算法第三章作业
    算法第三章上机实践报告
    算法第二章总结
    关于stl::sort--算法第二章作业
    算法第二章上机实践报告
    算法第一章作业
    1
    2020-2021-1 20209302毕慧敏《Linux内核原理与分析》第十二周作业
    2020-2021-1 20209302毕慧敏《Linux内核原理与分析》第十一周作业
  • 原文地址:https://www.cnblogs.com/yspm/p/13368620.html
Copyright © 2020-2023  润新知