题解: 袁绍的刁难

Posted grt-lty-love-forever

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解: 袁绍的刁难相关的知识,希望对你有一定的参考价值。

Description

  黄巾之乱后,郭嘉到了袁绍的统辖地区,结果袁绍想给我们的郭嘉大大一个下马威,且正值他招募将领的时候,于是乎,袁绍就让郭嘉大大去替他招募将领。
  这时候有很多很多的将领到袁绍处报到(别人家底厚,四世三公哪~~),每个将领的编号依次为1、2、3……N,第i个将领的武力值为3^(i-1)。
  袁绍需要我们的郭嘉大大招纳任意个将领,而郭嘉选中的将领有一个“总武力值”为各个将领的武力值之和。例如:郭嘉这一次招募了第一个将领和第三个将领,那么“总武力值”为1+9=10。
  袁绍想知道,他可以获得的第k大的“总武力值”是多少,请你帮助我们的郭嘉大大告诉袁绍这个第k大的“总武力值”。
  从文件中读入k,输出郭嘉能够获得的,第k大的“总武力值”。
 
 

Input

 数据包含n+1行,第一行读入n(n≤100)。以下n行每行包含一个k。

Output

 输出包含n行,每行输出一个对应的结果。
 

Sample1 Input

1
7
 

Sample1 Output

13
 

Sample2 Input

10

69

18

42

24

46

54

5

78

27

34

Sample2 Output

739

84

273

108

282

336

10

768

112

246

 

Data Constraint

 对于50%的输入文件,有k≤5000。
对于100%的输入文件,有k≤2^31-1。
 

Hint

样例说明:

郭嘉能够拿到的总武力值从小到大为1、3、4、9、10、12、13……所以第7大的总武力值是13。
 
 
                        
题目大意抽离出来就是有一个序列:1,3,9,27......其中第i个数等于3i-1现在给你一个k,求出这个序列中的数能组成的数中,第k大的数。
 
来找一下规律:
首先先把i=4时的序列能组成的数排列出来:1,3,4,9,10,12,13,27,28,30,31,36,37,39,40。
再枚举k 1-6(所列出来的数是原数列中的,不是能组成的数的数列,也就是不是上方这个)(括号中的数表示不取):
k=1  ans=1
k=2  ans=(1+)3=3
k=3  ans=1+3=4
k=4  ans=(1+3+)9=9
k=5  ans=1+(3+)9=10
k=6  ans=(1+)3+9=12
我们用第i个1表示取第i个数,用第i个0表示不取第i个数。
那么就变成了这样:
         1 3 9
k=1  ans=1
k=2  ans=0 1
k=3  ans=1 1
k=4  ans=0 0 1
k=5  ans=1 0 1
k=6  ans=0 1 1
我们发现如果把ans倒过来,并且把它当成二进制数,再把它变成十进制数,就是k!!!
如:ans=1 0 1 变为十进制就是 0×20+1×21+0×22+1×23=5=k
   ans=1 1 0 变为十进制就是 0×20+1×21+1×22+0×23=6=k
所以我们不妨这样想:
先定义一个数组t,t[i]=3i-1,可以打表打出来,也可以用快速幂在程序中计算,但要i枚举到多少呢?
我们看k的取值范为,k<=231-1,所以kmax=231-1=2147483647。
2147483647转换成二进制就是1111111111111111111111111111111,有31位,说明t数组中最多有31个数,所以i枚举到31就行,可以打表,也可以用快速幂在程序中计算,都不会超时。
定义一个h储存答案。
要求第k大的数,就要把k转换为二进制数,再翻转过来,如果第i位上的数为1,那么h+=t[i],可以边读边处理。
十进制转换成二进制的代码:
 1 int a[1000];
 2 int o=1,k;
 3 scanf("%d",&k);
 4 while(k!=0)
 5 {
 6     a[o]=k%2;
 7     k/=2;
 8     o++;
 9 }
10 for(int i=o-1;i>=1;i--)
11 printf("%d",a[i]);

这个需要倒叙输出,看到这,就联想到了前面的需要翻转,那我们为什么不直接不翻转来直接对应呢?想到这就可以更简化了,下面上代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
long long k,h;
long long t[35];
void dabiao();
int main()
{
    freopen("recruitment.in","r",stdin);//如果题目没要求可以注释掉
    freopen("recruitment.out","w",stdout);
    dabiao();
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int o=1;//记录现在对应的是第几位数
        h=0;
        scanf("%lld",&k);
        while(k!=0)
        {
            long long p;
            p=k%2;
            if(p==1) h+=t[o];
            k/=2;
            o++;
        }
        printf("%lld
",h);
    }
    return 0;
}
void dabiao()//打表
{
    t[1]=1;
    t[2]=3;
    t[3]=9;
    t[4]=27;
    t[5]=81;
    t[6]=243;
    t[7]=729;
    t[8]=2187;
    t[9]=6561;
    t[10]=19683;
    t[11]=59049;
    t[12]=177147;
    t[13]=531441;
    t[14]=1594323;
    t[15]=4782969;
    t[16]=14348907;
    t[17]=43046721;
    t[18]=129140163;
    t[19]=387420489;
    t[20]=1162261467;
    t[21]=3486784401;
    t[22]=10460353203;
    t[23]=31381059609;
    t[24]=94143178827;
    t[25]=282429536481;
    t[26]=847288609443;
    t[27]=2541865828329;
    t[28]=7625597484987;
    t[29]=22876792454961;
    t[30]=68630377364883;
    t[31]=205891132094649;
}

                                                                                                                                                                                                                                                                                         by:ルオ?テンイの锦依卫

                                                                                                                                                                                                                                                                                         未经作者允许,禁止转载!










以上是关于题解: 袁绍的刁难的主要内容,如果未能解决你的问题,请参考以下文章

2017.08.05NOIP提高组模拟赛B组

2017第42周日

Tarjan算法 消息的传递

题解:游历的路线”

为袁绍檄豫州文

一天杀了两千宦官(袁绍也曾仗义过,为东汉彻底除去了宦官祸害)