Hdu 5439 Aggregated Counting (2015长春网络赛 ACM/ICPC Asia Regional Changchun Online 找规律)

题目链接:

  Hdu 5439 Aggregated Counting

题目描述:

  刚开始给一个1,序列a是由a[i]个i组成,最后1就变成了1,2,2,3,3,4,4,4,5,5,5.......,最后问a[i]出现n次(i最大)时候,i最后一次出现的下标是多少?

解题思路:

  问题可以转化为求a[i] == n (i最大),数列前i项的和为多少。

  index:  1  2  3  4  5  6  7  8  9  10

  a:          1  2  2  3  3  4  4  4  5  5

  可以观察出:ans[1] = 1,  ans[i] = ans[i-1] + a[i]*i;

  但是n<=1e9,打不了这个庞大的表。进一步观察,可以发现a数组里面有很多的重复元素,辣么就可以对a数组里面的元素进行压缩存进b数组里面(出现次数为i的最后一个元素为b[i]):

  index:  1  2  3  4  5   6  7  8  9  10

  a:          1  2  2  3  3   4  4  4  5  5

  b:          1  3  5  8  11  15  19  23   28  33

  ans:       1  11  38    122  272  596  1086  

  1到出现次数为i的最后一个元素的区间和为ans[i],由a[]可以看出ans[i] = ans[i-1] + (b[i] + b[i-1] + 1) * (b[i] - b[i-1]) / 2 * i;

  每次查询的时候如果n不在b[i]里面,可以找到一个最接近n并且小于n的b[i],然后再套用一次等差数列求和即可。

  还有就是等差数列求和的时候,除以2要用到逆元处理一下。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 typedef __int64 LL;
 8 const int INF = 0x3f3f3f3f;
 9 const int maxn = 450000;
10 const int mod = 1000000007;
11 LL a[maxn], b[maxn], ans[maxn], num;
12 
13 LL quick_mod(LL x, LL n)
14 {
15     LL res = 1;
16 
17     while (n)
18     {
19         if (n % 2)
20             res = (res * x) % mod;
21 
22         x = (x * x) % mod;
23         n /= 2;
24     }
25     return res % mod;
26 }
27 void init ()
28 {
29     LL res = 1, j = 1, nu;
30 
31     a[0] = b[0] = 0;
32     a[1] = b[1] = 1;
33     a[2] = num = 2;
34     b[2] = 3;
35 
36     while (b[num] <= 1e9)
37     {
38         if (res <= num)
39         {
40             j ++;
41             res += a[j];
42         }
43 
44         while (res > num)
45         {
46             num ++;
47             a[num] = j;
48             b[num] = b[num-1] + a[num];
49         }
50 
51     }
52 
53     //printf ("%I64d %I64d\n", num, b[num]);
54 
55     ans[0] = 0;
56     ans[1] = 1;
57 
58     for (int i=2; i<=num; i++)
59          ans [i] = (ans[i-1] + (b[i] + b[i-1] + 1) % mod * a[i] % mod * i % mod * quick_mod(2, mod-2) % mod) % mod;
60 
61 }
62 
63 int main ()
64 {
65     LL t, n;
66     init ();
67     scanf ("%I64d", &t);
68 
69     while (t --)
70     {
71         scanf ("%I64d", &n);
72         LL pos = lower_bound (b, b+num, n) - b;
73 
74         if (b[pos] == n)
75         {
76             printf ("%I64d\n", ans[pos]);
77             continue;
78         }
79 
80         LL res = (ans[pos-1] + (b[pos-1] + n + 1) % mod * (n - b[pos-1]) % mod * pos % mod * quick_mod(2, mod-2) % mod) % mod;
81 
82         printf ("%I64d\n", res);
83     }
84     return 0;
85 }

 

posted @ 2015-09-17 09:06  罗茜  阅读(186)  评论(0编辑  收藏  举报