[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
17
18
Sample Output
6 3
16 15
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\n", mp[x].first, mp[x].second); else{ y = lower_bound(b + 1, b + cnt + 1, x) - (b + 1); printf("%d %d\n", tot + (x - y) * 2, tot + (x - y) * 2 - 1); } } return 0; }