Ural--1803(数学,高精度,压位)

2015-03-01 21:20:58

思路:这题的题意,简而言之就是给你n和k,让你求出前n个斐波那契数的各个数位上的数的和,进行排序后输出。

  考虑,首先k的范围2~10,没有问题,但是n最大可达到50000,而斐波那契数的增长非常快,40+就能爆int。

  所以要高精度+压位(不压位会T)

  借用下贴吧里的题解:关于如何确定压位的进制,我们取满足:base = k^x <= 10^6,(x为整数)的最大base。这个可以暴力求得。

  然后打表计算k进制下[0,base - 1]的各位数字和,剩下的就是高精度加法了。

  ※:关于如何比较快地打表计算,这里提供一种方法:

    当前要计算a,那么:sum[a] = sum[a / k] + a % k

    如果我们从0计算到base-1,那么在算a时,a/k必然算过,a/k比a少一位最低位,所以加上最低位a%k即可。

  算法复杂度:O(10^6 + 1741 * 50000)<--(from 贴吧)

  注意:这里可以用滚动数组,快速输出优化一下。。。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <string>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define MEM(a,b) memset(a,b,sizeof(a))
16 #define REP(i,n) for(int i=1;i<=(n);++i)
17 #define REV(i,n) for(int i=(n);i>=1;--i)
18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i)
20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
21 #define MP(a,b) make_pair(a,b)
22 
23 typedef long long ll;
24 typedef pair<int,int> pii;
25 const int INF = (1 << 30) - 1;
26 const int MAXN = 1000000;
27 
28 int n,k;
29 int Base;
30 ll sum[MAXN + 10];
31 
32 void Write(int v){
33     if(v>9) Write(v/10);
34     putchar(v%10+'0');
35 }
36 
37 struct BigInt{
38     int len,s[3000];
39     BigInt(){ len = 1; MEM(s,0); }
40     void clear(){ while(len > 1 && s[len - 1] == 0) --len; }
41 }bn[3];
42 
43 BigInt operator + (BigInt A,BigInt B){
44     A.len = max(A.len,B.len);
45     for(int i = 0; i < A.len; ++i)    A.s[i] += B.s[i];
46     for(int i = 0; i < A.len; ++i)    A.s[i + 1] += A.s[i] / Base,A.s[i] %= Base;
47     A.len++,A.clear();
48     return A;
49 }
50 
51 struct Node{
52     ll num;
53     int id;
54     bool operator < (const Node& B) const{
55         if(num == B.num) return id < B.id;
56         return num < B.num;
57     }
58 }nd[50010];
59 
60 int main(){
61     scanf("%d%d",&k,&n);
62     Base = k;
63     while(Base < MAXN) Base *= k;
64     Base /= k;
65     for(int i = 0; i < Base; ++i)    sum[i] = sum[i / k] + i % k;
66     int a = 0,b = 1,c = 2;
67     bn[a].s[0] = bn[b].s[0] = 1;
68     nd[1].num = nd[2].num = 1;
69     nd[1].id = 1;
70     nd[2].id = 2;
71     for(int i = 3; i <= n; ++i){
72         bn[c] = bn[a] + bn[b];
73         nd[i].num = 0;
74         nd[i].id = i;
75         for(int j = 0; j < bn[c].len; ++j)    nd[i].num += sum[bn[c].s[j]];
76         a = (a + 1) % 3;
77         b = (b + 1) % 3;
78         c = (c + 1) % 3;
79     }
80     sort(nd + 1,nd + n + 1);
81     for(int i = 1; i < n; ++i) Write(nd[i].id),putchar(' ');
82     Write(nd[n].id),putchar('\n');
83     return 0;
84 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4307633.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值