题目链接:hdu 5439 Aggregated Counting
1 2 2 3 3 4 4 4 5 5 5 6 6 6 6 7 7 7 7 8 8 8 8 .... 按照每个数出现的次数1出现了1次,2,3出现两次,以此类推,将次数取出作为序列,会发现对应的序列仍是 1 2 2 3 3 4 4 4 5 5 5 ....即原序列。第一次last我们可以根据前缀和求出,但是对于第二次last,由于第一次求完后的值会高达1e15,时间上肯定不允许利用前缀和去求解,但是前面讲到,按照每个数出现的次数形成新的序列是和原序列是相同的,那么假设我们考虑出现次数为4的数,(6, 7, 8),那么它们对应在序列中影响的位置长度为(6 + 7 + 8) * 4,而对应出现次数为4的数有几个,我们可以同过预处理打表得出。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 500000; const int mod = 1e9+7; struct Seg { ll l, r, s; Seg(ll l = 0, ll r = 0, ll s = 0): l(l), r(r), s(s) {} }seg[maxn]; int binsearch(int l, int r, int x) { while (l < r) { int mid = (l + r) >> 1; if (x > seg[mid].r) l = mid + 1; else r = mid;; } return l; } ll get(ll l, ll r) { return (r-l+1)*(r+l) / 2 % mod; } void init () { seg[1] = Seg(1, 1, 1); seg[2] = Seg(2, 3, 11); for (int i = 3; i < maxn; i++) { int v = binsearch(1, i-1, i); ll l = seg[i-1].r+1, r = seg[i-1].r+v; seg[i] = Seg(l ,r, (seg[i-1].s + get(l, r) * i % mod) % mod); } } int solve (int n) { int k = binsearch(1, maxn-1, n); return (seg[k-1].s + get(seg[k-1].r+1, n) * k % mod) % mod; } int main () { init(); int cas, n; scanf("%d", &cas); while (cas--) { scanf("%d", &n); printf("%d\n", solve(n)); } return 0; }