HDU 4282 A very hard mathematic problem [剪枝/二分]

这题暴力+剪枝就可以过,重点是一个强剪枝:当z=2时,用完全平方公式解,直接得出符合的解数。

或者二分y,因为当x、z确定时,f是y的增函数。

但是二分我不知道为什么用while(low<high)的时候,写不对。。[mark]


1、暴力+剪枝

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef __int64 int64;
#define INF (1<<30)
const double eps = 1e-8;
#define bug(s) cout<<#s<<"="<<s<<" "

//	z = [2, 30].
//	把z=2的提出来单独用 完全平方公式 考虑,是强剪枝。

int64 ex(int x, int y)	//x^y	,返回int64,为判断爆int32留有余地
{
	int64 ret = 1, now = x;
	for( ; y; y>>=1, now*=now)
	{
		if(y&1)
			ret*=now;
	}
	return ret;
}

int main()
{
	int k;
	while(scanf("%d", &k)!=-1 && k)
	{
		int64 ans = 0;
		int qr = (int)sqrt(k*1.0);
		if(qr*qr == k)		// 最优化剪枝,当z=2时。
		{
			ans += (qr-1)>>1;
		}
		FOR(z, 3, 30)
		{
			for(int x = 1; ; x++)
			{
				int64 t1 = ex(x, z);
				if(t1 + ex(x+1, z) + x*(x+1)*z > k) break;	//可行性剪枝
				for(int y = x+1;  ; y++)
				{
					int64 f = t1 + ex(y, z) + x*y*z;
					if(f > k) break;	//可行性剪枝
					else if(f == k)
					{
						//bug(z);bug(x);bug(y)<<endl;
						ans++;
						break;	//x、z确定后,f是y的增函数,显然 y是唯一的。	//可行性剪枝
					}
				}
			}
		}
		printf("%I64d\n", ans);
	}
}

2、二分

用while(low<=high)的写法,AC

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef __int64 int64;
#define INF (1<<30)
const double eps = 1e-8;
#define bug(s) cout<<#s<<"="<<s<<" "

//	z = [2, 30].

int64 ex(int x, int y)	//x^y	,返回int64,为判断爆int32留有余地
{
	int64 ret = 1, now = x;
	for( ; y; y>>=1, now*=now)
	{
		if(y&1)
			ret*=now;
	}
	return ret;
}

int main()
{
	int k;
	while(scanf("%d", &k)!=-1 && k)
	{
		//bug(sqrt((((int64)(1)<<31)-1)*1.0)-1)<<endl;		// max(y) = 46340

		int64 ans = 0;
		int qr = (int)sqrt(k*1.0);
		if(qr*qr == k)		// 最优化剪枝,当z=2时。
		{
			ans += (qr-1)>>1;
		}
		FOR(z, 3, 30)
		{
			for(int x = 1; ; x++)
			{
				int64 t1 = ex(x, z);
				if(t1 + ex(x+1, z) + x*(x+1)*z > k) break;	//可行性剪枝

				//for(int y = x+1;  ; y++)
				//{
				//	int64 f = t1 + ex(y, z) + x*y*z;
				//	if(f > k) break;	//可行性剪枝
				//	else if(f == k)
				//	{
				//		//bug(z);bug(x);bug(y)<<endl;
				//		ans++;
				//		break;	//x、z确定后,f是y的增函数,显然 y是唯一的。	//可行性剪枝
				//	}
				//}

				//int low = x+1, high = 46340;
				//while(low<high)
				//{
				//	int mid = (low+high)>>1;
				//	int64 f = t1 + ex(mid, z) + x*mid*z;
				//	//if(f > k || ex(mid, z)<0 || x*mid*z<0 || f<0) high = mid;
				//	if(f > k || f<0) high = mid;
				//	else if(f < k) low = mid+1;
				//	else if(f == k) { low = mid; break; }
				//}
				////bug(x);bug(z);bug(low)<<endl;
				//if(t1 + ex(low, z) + x*low*z == k)
				//{
				//	ans++;
				//}

				while(low<=high)
				{
					int mid = (low+high)>>1;
					int64 f = t1 + ex(mid, z) + x*mid*z;
					//if(f > k || ex(mid, z)<0 || x*mid*z<0 || f<0) high = mid-1;	//保险点。。
					if(f > k || f<0) high = mid-1;
					else if(f<k) low = mid+1;
					else
					{
						ans++;
						break;
					}
				}
			}
		}
		printf("%I64d\n", ans);
	}
}

3、二分, while(low<high)的写法, wa

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef __int64 int64;
#define INF (1<<30)
const double eps = 1e-8;
#define bug(s) cout<<#s<<"="<<s<<" "

//	z = [2, 30].

int64 ex(int x, int y)	//x^y	,返回int64,为判断爆int32留有余地
{
	int64 ret = 1, now = x;
	for( ; y; y>>=1, now*=now)
	{
		if(y&1)
			ret*=now;
	}
	return ret;
}

int main()
{
	int k;
	while(scanf("%d", &k)!=-1 && k)
	{
		//bug(sqrt((((int64)(1)<<31)-1)*1.0)-1)<<endl;		// max(y) = 46340

		int64 ans = 0;
		int qr = (int)sqrt(k*1.0);
		if(qr*qr == k)		// 最优化剪枝,当z=2时。
		{
			ans += (qr-1)>>1;
		}
		FOR(z, 3, 30)
		{
			for(int x = 1; ; x++)
			{
				int64 t1 = ex(x, z);
				if(t1 + ex(x+1, z) + x*(x+1)*z > k) break;	//可行性剪枝

				//for(int y = x+1;  ; y++)
				//{
				//	int64 f = t1 + ex(y, z) + x*y*z;
				//	if(f > k) break;	//可行性剪枝
				//	else if(f == k)
				//	{
				//		//bug(z);bug(x);bug(y)<<endl;
				//		ans++;
				//		break;	//x、z确定后,f是y的增函数,显然 y是唯一的。	//可行性剪枝
				//	}
				//}

				int low = x+1, high = 46340;
				while(low<high)
				{
					int mid = (low+high)>>1;
					int64 f = t1 + ex(mid, z) + x*mid*z;
					//if(f > k || ex(mid, z)<0 || x*mid*z<0 || f<0) high = mid;
					if(f > k || f<0) high = mid;
					else if(f < k) low = mid+1;
					else if(f == k) { low = mid; break; }
				}
				//bug(x);bug(z);bug(low)<<endl;
				if(t1 + ex(low, z) + x*low*z == k)
				{
					ans++;
				}

				//while(low<=high)
				//{
				//	int mid = (low+high)>>1;
				//	int64 f = t1 + ex(mid, z) + x*mid*z;
				//	//if(f > k || ex(mid, z)<0 || x*mid*z<0 || f<0) high = mid-1;	//保险点。。
				//	if(f > k || f<0) high = mid-1;
				//	else if(f<k) low = mid+1;
				//	else
				//	{
				//		ans++;
				//		break;
				//	}
				//}
			}
		}
		printf("%I64d\n", ans);
	}
}


你可能感兴趣的:(优化)