[BZOJ4725][POI2017]Reprezentacje ró?nicowe

4725: [POI2017]Reprezentacje ró?nicowe

Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 122  Solved: 59 [Submit][Status][Discuss]

Description

给定一个数列a:
当n<=2时,a[n]=n
当n>2,且n是奇数时,a[n]=2a[n-1]
当n>2,且n是偶数时,a[n]=a[n-1]+r[n-1]
其中r[n-1]=mex(|a[i]-a[j]|)(1<=i<=j<=n-1),mex{S}表示最小的不在S集合里面的非负整数。
数列a的前若干项依次为:1,2,4,8,16,21,42,51,102,112,224,235,470,486,972,990,1980。
可以证明,对于任意正整数x,只存在唯一一对整数(p,q)满足x=a[p]-a[q],定义为repr(x)。
比如repr(17)=(6,3),repr(18)=(16,15)。
现有n个询问,每次给定一个正整数x,请求出repr(x)。

Input

第一行包含一个正整数n(1<=n<=10^5)。
接下来n行,每行一个正整数x(1<=x<=10^9),表示一个询问。

Output

输出n行,每行两个正整数p,q,依次回答每个询问。

Sample Input

2
17
18

Sample Output

6 3
16 15
 
发现数列增长的很快
然后把$10^9$以内的$a$全部打出来
若一个$x$的值已经被减出来了就直接输出
没有的话发现肯定是没打出来的且相邻的两项$a$差出来的
然后根据那个$mex$的性质,计算一下还需要多少项即可
#pragma GCC optimize("O2")
#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
char buf[10000000], *ptr = buf - 1;
inline int readint(){
    int n = 0;
    while(*++ptr < '0' || *ptr > '9');
    while(*ptr <= '9' && *ptr >= '0') n = (n << 1) + (n << 3) + (*ptr++ & 15);
    return n;
}
int a[100], b[1000000], cnt = 0;
map<int, pair<int, int> > mp;
int main(){
    fread(buf, sizeof(char), sizeof(buf), stdin);
    mp.clear();
    a[1] = 1;
    a[2] = 2;
    mp[1] = make_pair(2, 1);
    int last, tot;
    for(last = 1, tot = 3; ; tot++){
        if(tot & 1) a[tot] = a[tot - 1] + a[tot - 1];
        else{
            while(mp.count(last)) last++;
            a[tot] = a[tot - 1] + last;
        }
        for(int j = 1; j < tot; j++)
            if(!mp.count(a[tot] - a[j]))
                mp[a[tot] - a[j]] = make_pair(tot, j);
        if(!(tot & 1) && a[tot] > 1000000000) break;
    }
    map<int, pair<int, int> >::iterator it;
    for(it = mp.begin(); it != mp.end(); ++it)
        b[++cnt] = it -> first;
    int n = readint(), x, y;
    while(n--){
        x = readint();
        if(mp.count(x)) printf("%d %d
", mp[x].first, mp[x].second);
        else{
            y = lower_bound(b + 1, b + cnt + 1, x) - (b + 1);
            printf("%d %d
", tot + (x - y) * 2, tot + (x - y) * 2 - 1);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ruoruoruo/p/7636801.html