BZOJ 3614 Heoi2014 逻辑翻译 分治 = =HEOI2014全AC达成?

9 篇文章 0 订阅

题目大意:给定一个含有n个变量的2^n项的多项式,将每个变量分别选-1和1代入求值,求多项式的各项系数

《论一道题究竟如何出才能同时卡时间卡内存卡精度卡输入卡输出卡评测》

很久之前盯着这道题看了很长时间……直到今天我才发现这题原来是道傻逼题。。。

我们用三个变量举例

假设f(x)=a0x1x2x3+a1x1x2+a2x1x3+a3x2x3+a4x1+a5x2+a6x3+a7

那么我们把含有x1的项提出来 得到

f(x)=x1(a0x2x3+a1x2+a2x3+a4)+(a3x2x3+a5x2+a6x3+a7)

然后我们把x1=1和x1=-1分别带进去,两个式子加一下除以2,加号的左边“Duang”地一下就没啦!

然后我们把x1=1和x1=-1分别带进去,两个式子减一下除以2,加号的右边“Duang”地一下也没啦!

然后。。。。然后。。。然后没有然后辣。。。递归做到底就是了。。。

于是这题考的实际上是如何处理题目中遇到的各种恶心情况?

果断BZ倒数第一,第十个点本机跑了9s+,于是我其实根本不算AC掉这题了?

最后一个点输出46MB真是吓死爹了

留念= =


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define EPS 1e-7
using namespace std;
struct OStream{
	#define L (1<<20)
	char buffer[L],*S;
	OStream()
	{
		S=buffer;
	}
	void Putchar(char c)
	{
		*S++=c;
		if(S==buffer+L)
		{
			fwrite(buffer,1,L,stdout);
			S=buffer;
		}
	}
	void Print(int x)
	{
		static int stack[20],top;
		if(x<0)
			Putchar('-'),x=-x;
		if(x==0)
			Putchar('0');
		while(x)
			stack[++top]=x%10,x/=10;
		while(top)
			Putchar(stack[top--]+'0');
	}
	~OStream()
	{
		fwrite(buffer,1,S-buffer,stdout);
	}
}os;
struct Frac{
	int a,b;
	Frac() {}
	Frac(long long _,long long __=1)
	{
		int gcd=__gcd(_,__);
		a=_/gcd;
		b=__/gcd;
		if(b<0) a=-a,b=-b;
	}
	friend istream& operator >> (istream &_,Frac &x)
	{
		double a;
		scanf("%lf",&a);
		x=Frac((long long)(a*100+(a<0?-EPS:EPS)),100);
		return _;
	}
	friend Frac operator + (const Frac &x,const Frac &y)
	{
		int gcd=__gcd(x.b,y.b),lcm=x.b/gcd*y.b;
		Frac re((long long)x.a*(lcm/x.b)+(long long)y.a*(lcm/y.b),lcm);
		return re;
	}
	friend Frac operator - (const Frac &x,const Frac &y)
	{
		int gcd=__gcd(x.b,y.b),lcm=x.b/gcd*y.b;
		Frac re((long long)x.a*(lcm/x.b)-(long long)y.a*(lcm/y.b),lcm);
		return re;
	}
	friend Frac operator / (const Frac &x,int y)
	{
		Frac re(x.a,x.b*y);
		return re;
	}
	friend ostream& operator << (ostream &_,const Frac &x)
	{
		if(x.b==1)
			os.Print(x.a);
		else
			os.Print(x.a),os.Putchar('/'),os.Print(x.b);
		return _;
	}
};
int n;
struct abcd{
	int sta;
	Frac val;
	friend istream& operator >> (istream &_,abcd &a)
	{
		int i;
		static char s[30];
		scanf("%s",s+1);
		for(i=1;i<=n;i++)
			(a.sta<<=1)|=(s[i]=='+'?1:0);
		cin>>a.val;
		return _;
	}
	bool operator < (const abcd &a) const
	{
		return sta > a.sta;
	}
}a[1<<20];

//我真是日了我家那只萌萌哒的POI了= =
void Divide_And_Conquer(abcd a[],int n)
{
	int i;
	if(n==1) return ;
	abcd *l=a,*r=a+(n>>1);
	for(i=0;i<n>>1;i++)
	{
		Frac x=l[i].val,y=r[i].val;
		l[i].val=(x-y)/2;
		r[i].val=(x+y)/2;
	}
	Divide_And_Conquer(l,n>>1);
	Divide_And_Conquer(r,n>>1);
	abcd C=a[n>>1];
	for(i=n>>1;i;i--)
		a[i]=a[i-1];
	a[0]=C;
}
int main()
{
	int i,j;
	cin>>n;
	for(i=0;i<1<<n;i++)
		cin>>a[i];
	sort(a,a+(1<<n));
	Divide_And_Conquer(a,1<<n);
	for(i=0;i<1<<n;i++)
	{
		if(!a[i].val.a)
			continue;
		cout<<a[i].val;
		if(i) os.Putchar(' ');
		for(j=1;j<=n;j++)
			if(a[i].sta&(1<<n-j))
				os.Putchar('x'),os.Print(j);
		os.Putchar('\n');
	}
	return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值