codeforces.com/contest/325/problem/B

时间:2021-03-14 11:52:14

http://codeforces.com/contest/325/problem/B

B. Stadium and Games
time limit per test

1 second

memory limit per test

256 megabytes

input

standard input

output

standard output

Daniel is organizing a football tournament. He has come up with the following tournament format:

  1. In the first several (possibly zero) stages, while the number of teams is even, they split in pairs and play one game for each pair. At each stage the loser of each pair is eliminated (there are no draws). Such stages are held while the number of teams is even.
  2. Eventually there will be an odd number of teams remaining. If there is one team remaining, it will be declared the winner, and the tournament ends. Otherwise each of the remaining teams will play with each other remaining team once in round robin tournament (if there are x teams, there will be codeforces.com/contest/325/problem/B games), and the tournament ends.

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.

Input

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.

Output

Print all possible numbers of invited teams in ascending order, one per line. If exactly n games cannot be played, output one number: -1.

Sample test(s)
input
3
output
3
4
input
25
output
20
input
2
output
-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;
}