比赛前三天蒟蒻打了一个暴力想要看看数据强度的时候,发现正解挂了!!!

然后调了出题人一个下午终于肝出来了..

(蒟蒻出题人再也不出毒瘤数据结构题了..)

首先我们可以预处理出11~10^7107所有的数能分解的质因子个数..

这个可以用欧拉线性筛筛出来..虽然这个并不是积性函数..

我们可以预处理出斐波那契数列的前4040项..这么多已经够用了..

然后我们把第ii项改成原来的第ii项减去第i-1i1项..

这样子就变成了与上一个隔多少个就再取一个数了..

比如说原来的斐波那契数列是:1, 2, 3, 5, 8...

然后我们把它魔改成:1, 1, 1, 2, 3...(实际上是右移了两下..)

对于第一行来说,上面五个数就表示: 第一个要选的是上一个(没有为00)的后一位: 11

第二个要选的就是上一个(11)的后一位: 22

第三个要选的就是上一个(22)的后一位: 33

第四个要选的就是上一个(33)的后两位: 55

第五个要选的就是上一个(55)的后三位: 88

...

然而还是斐波那契数列..

这个有个\piπ(pi)用啊!!!

当然有用啊..

改成了这样后我们就可以搞6060的暴力辣!!!

首先我们发现前10的分组是这样的:

12345678910...
1 1 1 2 1 2 2 1 3 2 ...

没有发现什么吗??

然后让我们把之前的候选的东西放进去:

数字12345678910...
归属 1 1 1 2 1 2 2 1 3 2 ...
11行的候选 1 1 1 2 1 3 2 1 5 4 ...
22行的候选 (1)- (1)- (1)- 1 (1)- 1 1 (1)- 2 1 ...
33行的候选 (1)- (1)- (1)- (1)- (1)- (1)- (1)- (1)- 1 (1)- ...

当然,这里面打'-'的表示不可能选到的..括号表示没有改变(或者说是无关的)候选..

然后一个很显然的一点: 一个数字如果属于前面的行是不可能影响到后面的行的候选的..

而且从数字为10的时候我们可以看出:如果当前候选的有多个为1的(第22行和第33行),优先选择行数小的(第22行),并且行数大的(第33行)候选不改变(虽然这里貌似看不出来,但是可以自己多写写就可以看出来了)..并且不是可选行且比当前选择行(第22行)小的(第11行)候选也要减..

不信可以自己试试..Markdown的表格真难写..

然后这个就可以离线询问然后O(NK)O(NK)模拟了..

至于正解..

我们发现这个就是一个区间最小值,区间减法,这个直接用线段树搞就好了..

附上一个小优化:如果当前10^4104的行内候选都大于11(假设是xx),那么后面x-1x1的数都肯定不是这10^4104行内的东西..所以可以直接在枚举NN的时候加上x-1x1,然后11~10^4104区间减去x-1x1就好了..

附上丑陋而异常臃肿的代码..

#include <bits/stdc++.h>

using namespace std;

#define reg register
#define enter putchar('\n')
#define ls (Node << 1)
#define rs ((Node << 1) | 1)
#define MAXN 5000000
#define MAXT 1000000
#define MAXK 10000

const char FI[] = "queue.in";
const char FO[] = "queue.out";

typedef short sh;

inline int Min(reg int a, reg int b) { return a < b ? a : b; }

inline int read() {
    reg int s = 0, t = 1; reg char ch = getchar();
    while(ch > '9' || ch < '0') t *= ch == '-' ? -1 : 1, ch = getchar();
    while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
    return s * t;
}

struct Node {
    sh k;
    int n;
    int id;
}Ask[MAXT + 1];

bool operator < (Node a, Node b) {
    return a.n < b.n;
}

int T;
sh s[MAXN + 1];
int res[MAXT + 1];
int fib[50] = {1, 1};
int prime[40 * MAXK];
bitset<MAXN + 1>Check;

int Id[MAXK << 5];
int pos[MAXK << 5];
int tag[MAXK << 5];
int Tree[MAXK << 5];

inline void init() {
    reg int tot = 0;
    for(reg int i = 2; i <= MAXN; i++) {
        if(!Check[i]) prime[++tot] = i, s[i] = 1;
        for(reg int j = 1; j <= tot && i * prime[j] <= MAXN; j++) {
            Check[i * prime[j]] = 1, s[i * prime[j]] = s[i] + 1;
            if(i % prime[j] == 0) break;
        }
    }
    for(reg int i = 2; i < 50; i++) fib[i] = fib[i - 1] + fib[i - 2];
    for(reg int i = 49; i > 1; i--) fib[i] -= fib[i - 1];
    T = read();
    for(reg int i = 1; i <= T; i++)
        Ask[i].n = read(), Ask[i].k = read(), Ask[i].id = i;
    sort(Ask + 1, Ask + T + 1);
}

inline void build(reg int Node, reg int L, reg int R) {
    Tree[Node] = 1;
    if(L == R) {
        Id[Node] = L, pos[Node] = Node;
        return ;
    }
    reg int mid = (L + R) >> 1;
    build(ls, L, mid), build(rs, mid + 1, R);
    pos[Node] = pos[ls];
}

inline void Add(reg int Node, reg int L, reg int R, reg int l, reg int r, reg int k) {
    if(l <= L && R <= r) {
        Tree[Node] += k, tag[Node] += k;
        return ;
    }
    Tree[ls] += tag[Node]; tag[ls] += tag[Node];
    Tree[rs] += tag[Node]; tag[rs] += tag[Node];
    tag[Node] = 0;
    reg int mid = (L + R) >> 1;
    if(l <= mid) Add(ls, L, mid, l, r, k);
    if(r > mid) Add(rs, mid + 1, R, l, r, k);
    Tree[Node] = min(Tree[ls], Tree[rs]);
    pos[Node] = (Tree[Node] == Tree[ls] ? pos[ls] : pos[rs]);
}

int main() {
    init();
    reg int M = Ask[T].n;
    reg int id = 1;
    reg int g[MAXK + 1];
    reg int ans[MAXK + 1]; memset(ans, -1, sizeof(ans));
    for(reg int i = 1; i <= 10000; i++) g[i] = 1;
    build(1, 1, 10000);
    for(reg int i = 1, Mi, add, ID; id <= T && i <= M; i++) {
        Mi = pos[1], ID = Id[Mi];
        Add(1, 1, 10000, ID, ID, 0);
        add = Tree[Mi];
        Add(1, 1, 10000, 1, ID, -add);
        if(add > 1 && ID < 10000)
            Add(1, 1, 10000, ID + 1, 10000, 1 - add);
        Add(1, 1, 10000, ID, ID, fib[++g[ID]]);
        while(id <= T && Ask[id].n < i + add - 1) res[Ask[id].id] = ans[Ask[id].k], id++;
        i += add - 1;
        if(i > M || id > T) break;
        ans[ID] += s[i] + (ans[ID] < 0);
        while(id <= T && Ask[id].n <= i) res[Ask[id].id] = ans[Ask[id].k], id++;
    }
    for(reg int i = 1; i <= T; i++) printf("%d", res[i]), enter;
    return 0;
}