HDU5439 Aggregated Counting (找规律+预处理+二分)

Aggregated Counting

Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 666    Accepted Submission(s): 302


Problem Description
Aggregated Counting Meetup (ACM) is a regular event hosted by Intercontinental Crazily Passionate Counters (ICPC). The ICPC people recently proposed an interesting sequence at ACM2016 and encountered a problem needed to be solved.

The sequence is generated by the following scheme.
1. First, write down 1, 2 on a paper.
2. The 2nd number is 2, write down 2 2’s (including the one originally on the paper). The paper thus has 1, 2, 2 written on it.
3. The 3rd number is 2, write down 2 3’s. 1, 2, 2, 3, 3 is now shown on the paper.
4. The 4th number is 3, write down 3 4’s. 1, 2, 2, 3, 3, 4, 4, 4 is now shown on the paper.
5. The procedure continues indefinitely as you can imagine. 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, . . . .

The ICPC is widely renowned for its counting ability. At ACM2016, they came up with all sorts of intriguing problems in regard to this sequence, and here is one: Given a positive number n , First of all, find out the position of the last n that appeared in the sequence. For instance, the position of the last 3 is 5, the position of the last 4 is 8. After obtaining the position, do the same again: Find out the position of the last (position number). For instance, the position of the last 3 is 5, and the position of the last 5 is 11. ICPC would like you to help them tackle such problems efficiently.

 

Input
The first line contains a positive integer T,T2000 , indicating the number of queries to follow. Each of the following T lines contain a positive number n(n109) representing a query.
 

Output
Output the last position of the last position of each query n . In case the answer is greater than 1000000006 , please modulo the answer with 1000000007 .
 

Sample Input
  
  
3 3 10 100000
 

Sample Output
  
  
11 217 507231491
 

Source

题意:f(n)表示序列中n的最后的位置,求f(f(n))。
分析:可以令n=1+2+2+3+3+......+ i    这个序列的长度为p
那么a[n]=1*1+2*2+3*2+...... + p*i 
那么不难发现a[a[n]] = 1*1 + (2+3)*2 + (4+5)*3 + (6+7+8)*4 + ... + (pre+1 + pre+2 + ... + pre+b[p] ) * p
b[p]为p在原序列中出现的次数
pre 是 第p-1项的pre + b[p-1]
pre,b[p]这些值都可以预处理算出   每次询问可以O(1)算出答案

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int INF = 1e9;
const int MOD = 1e9+7;
#define ll long long
#define CL(a,b) memset(a,b,sizeof(a))
#define lson (i<<1)
#define rson ((i<<1)|1)
#define MAXN 438744

int a[MAXN+5],b[MAXN+5];
int sum[MAXN+5],dp[MAXN+5],pre[MAXN+5];
int sz,val;

int add(int x, int y)
{
    x += y;
    if(x >= MOD) x -= MOD;
    return x;
}
int po(int x, int n)
{
    int ans = 1;
    int temp = x;
    while(n)
    {
        if(n&1) ans = (ll)ans*temp%MOD;
        temp = (ll)temp*temp%MOD;
        n >>= 1;
    }
    return ans;
}

int main()
{
    val = po(2, MOD-2);
    a[1] = 1;
    a[2] = 2;
    a[3] = 2;
    int sz=3;
    for(int i=3; ; i++)
    {
        int cnt = a[i];
        while(cnt)
        {
            a[++sz] = i;
            cnt--;
            if(sz >= MAXN) break;
        }
        if(sz >= MAXN) break;
    }
    for(int i=1; i<=MAXN; i++)
    {
        sum[i] = sum[i-1]+a[i];
        if(sum[i] >= INF) break;
    }
    for(int i=1; i<=MAXN; i++)
    {
        dp[i] = add(dp[i-1], (ll)(add(add(add(pre[i-1], 1), pre[i-1]), a[i]))*a[i]%MOD*i%MOD*val%MOD);
        pre[i] = add(pre[i-1], a[i]);
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        int l=1, r=MAXN;
        int pos;
        while(l <= r)
        {
            int mid = (l+r)>>1;
            if(n <= sum[mid])
            {
                pos = mid;
                r = mid-1;
            }
            else l = mid+1;
        }
        int x = n-sum[pos-1];
        int ans = add(dp[pos-1], (ll)(add(add(add(pre[pos-1], 1), pre[pos-1]), x))*x%MOD*pos%MOD*val%MOD);
        printf("%d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值