分析题目后,得到要求的是最接近n的一个数,并且这个数字能写成1+2+3+....+x = ans这种形式。
要求的是最大的值。
这题就直接二分去做吧。二分出一个f(mid)<=n的最大值。
最后的end就是所求的f(end)
为什么呢?,我来分析下我这个二分是怎么实现的
while (begin<=end) { LL mid = (begin + end) / 2; if (f(mid) == n) { printf ("Case #%d: %lld\n",++ff,n); return ; } if (f(mid) < n) { begin = mid+1; //去找一个可能比n大的 } else end = mid-1; //如果比n大了的话。就回来找一个小的。 //cout<<f(mid)<<endl; }
当f(mid)<n的时候 begin = mid+1,如果这个时候[mid+1,end]的所有数字的f()值都大于n呢?那么,最后一步就肯定是begin=end,然后end-1.去到的是第一个小于n的f()值。
其他也是一样分析啦。
f(end),第一个小于n的f值。
f(begin),第一个大于n的f值。考虑最后一步begin==end的时候,就能看清楚了。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> LL f(LL x) { if (x&1) { return (x+1)/2*x; } else return x/2*(x+1); } int ff; void work () { LL n; cin>>n; LL begin=1,end=2e9; while (begin<=end) { LL mid = (begin + end) / 2; if (f(mid) == n) { printf ("Case #%d: %lld\n",++ff,n); return ; } if (f(mid) < n) { begin = mid+1; //去找一个可能比n大的 } else end = mid-1; //如果比n大了的话。就回来找一个小的。 //cout<<f(mid)<<endl; } printf ("Case #%d: %lld\n",++ff,f(end)); return ; } int main() { #ifdef local freopen("data.txt","r",stdin); #endif int t; cin>>t; while(t--) work(); return 0; }
时间: 2024-10-03 23:15:28