1. 程式人生 > >Aggregated Counting(找規律 + 預處理)

Aggregated Counting(找規律 + 預處理)

include reg pre 發現 sdn scan ble 16px div

Aggregated Counting

轉 : https://blog.csdn.net/cq_phqg/article/details/48417111

題解:

可以令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; }

Aggregated Counting(找規律 + 預處理)