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