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