• codeforces.com/contest/325/problem/B


    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  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 cincout 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
    ",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;
    }


  • 相关阅读:
    ORA-32004 的错误处理
    告警日志
    ORACLE 归档日志打开关闭方法
    oracle归档日志配置查询
    教你如何阅读Oracle数据库官方文档
    使用Oracle安装账户登录数据库
    poj 2186 (强连通缩点)
    poj 2516 (费用流)
    STL集合容器set按照由小到大或者由大到小的顺序存放元素
    Android项目 手机安全卫士(代码最全,注释最详细)之十二 设置中心的界面
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3190202.html
Copyright © 2020-2023  润新知