菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
474
0

BZOJ3771 Triple

原创
05/13 14:22
阅读数 67874

Description

link

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

\(n \le 40000\)

Solution

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

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

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

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

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

显然不对……

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

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

三种就是\(\frac {A^3-3\times A\times B +2\times 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\n",i,(int)(A[i].x+0.5));  
		return 0;
	}
}
signed main(){return yspm::main();}

发表评论

0/200
474 点赞
0 评论
收藏
为你推荐 换一批