http://codeforces.com/contest/325/problem/B
Daniel is organizing a football tournament. He has come up with the following tournament format:
For example, if there were 20 teams initially, they would begin by playing 10 games. So, 10 teams would be eliminated, and the remaining 10 would play 5 games. Then the remaining 5 teams would play 10 games in a round robin tournament. In total there would be 10+5+10=25 games.
Daniel has already booked the stadium for n games. Help him to determine how many teams he should invite so that the tournament needs exactly n games. You should print all possible numbers of teams that will yield exactly n games in ascending order, or -1 if there are no such numbers.
The first line contains a single integer n (1 ≤ n ≤ 1018), the number of games that should be played.
Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64dspecifier.
Print all possible numbers of invited teams in ascending order, one per line. If exactly n games cannot be played, output one number: -1.
3
3 4
25
20
2
-1
这道题让我明白了long double在一些编译器里是128位,至少在codeforcres里64位的数的平方不会溢出
题目意思是:有许多队伍玩游戏
1.如果队伍数量是偶数个,则每两个队伍玩一个游戏并要淘汰一对,也就是说有x个队伍玩了s/2个游戏并且剩下x/2个队
2.如果队伍数量是奇数个,则美两个队伍玩一场游戏然后结束,即玩x*(x-1)/2个游戏然后结束
题目输入玩的游戏数量n,求可能有多少队伍玩游戏,按队伍从小到大输出,不存在就输出-1.
分析:n<=10^18<2^64,所以假设有s队伍数量,则s可能二分的次数是0~60次然后得到一个奇数x,所以总的游戏数就是x*(x-1)/2+x+2x+4x+8x+....+2^(i-1)x;//i表示二分的次数
令x*(x-1)/2+x+2x+4x+8x+....+2^(i-1)x=n ==> x^2+(2^(i+1)-3)x = 2n,所以只要求出x就能求出相应的s,然后进行排序后输出就行了
求x有两种方法;
1是直接用求根公式,由于b^2-4ac这步b^2可能会超出64位,所以算这步要用long double类型
2是对x进行二分查找,查找的范围left=1,right=(2^60/b,2000000000)即可;//b表示2^(i+1)-3,减3可以忽略,2000000000是由于x^2<=2n<=2*10^18
第一种方法:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<queue> #include<algorithm> #include<map> #include<cmath> #include<iomanip> #define INF 99999999 using namespace std; const int MAX=65; __int64 s[MAX]; int main(){ cout<<sizeof(long long int)<<endl; __int64 n; while(scanf("%I64d",&n)!=EOF){ int k=0; for(int i=0;i<60;++i){ long double b=(1ll<<(i+1))-3; __int64 x=(-b+sqrt(b*b+8*n))/2; if(x%2 == 0 || x*(x-1)/2+(1ll<<i)*x-x != n)continue; s[k++]=(1ll<<i)*x; } sort(s,s+k); for(int i=0;i<k;++i)printf("%I64d\n",s[i]); if(k == 0)cout<<"-1"<<endl; } return 0; }
第二种方法:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<queue> #include<algorithm> #include<map> #include<iomanip> #define INF 99999999 using namespace std; const int MAX=61; __int64 s[MAX]; __int64 search(int i,__int64 n){ __int64 left=1,right=min(1ll<<(60-i),(__int64)2000000000); while(left<=right){ __int64 mid=left+right>>1; if( mid*mid+(1ll<<(i+1))*mid-3*mid>2*n )right=mid-1; else if( mid*mid+(1ll<<(i+1))*mid-3*mid<2*n )left=mid+1; else return mid; } return -1; } int main() { __int64 n; while(cin>>n){ int k=0; for(int i=0;i<60;++i){ __int64 x=search(i,n); if(x != -1 && x%2 == 1)s[k++]=(1ll<<i)*x; } if(k == 0)cout<<"-1"<<endl; else{ for(int i=0;i<k;++i)cout<<s[i]<<endl; } } return 0; }