Aggregated Counting
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 50 Accepted Submission(s): 19
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,T≤2000, indicating the number of queries to follow. Each of the following
T lines contain a positive number
n(n≤109) 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
Sample Output
题解:
可以令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,b[p]这些值都可以预处理算出 每次询问可以O(1)算出答案
pre 是 第p-1项的pre + b[p-1]
比赛没时间想了哎,赛后一推就出来了,果然还是太弱- -!
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MOD = (int)1e9+7;
const int INF = (int)1e9;
const int MAXN = 438744;
int a[MAXN+5];
int b[MAXN+5];
int sum[MAXN+5];
int dp[MAXN+5];
int 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;
}