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

来源:互联网 发布:vmware使用教程linux 编辑:程序博客网 时间:2024/05/16 10:44

这题暴力+剪枝就可以过,重点是一个强剪枝:当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) = 46340int64 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) = 46340int64 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);}}


原创粉丝点击