题目
边界调到死,输入输出交互对调试端及其不友好
题意:
有
n
(
≤
1
e
3
)
n(\leq1e3)
n(≤1e3)个值域在
[
0
,
L
]
[0,L]
[0,L]的函数满足
∀
i
∈
[
1
,
n
]
,
x
∈
[
1
,
1
e
18
]
,
f
i
(
0
)
=
0
,
f
i
(
1
e
18
)
=
L
,
f
i
(
x
)
−
f
i
(
x
−
1
)
∈
[
0
,
1
]
\forall i\in [1,n],x\in[1,1e18] ,f_i(0)=0,f_i(1e18)=L,f_i(x)-f_i(x-1) \in[0,1]
∀i∈[1,n],x∈[1,1e18],fi(0)=0,fi(1e18)=L,fi(x)−fi(x−1)∈[0,1],每次操作可以询问一个函数在一个点的值,在
2
e
5
2e5
2e5次操作内求出一组划分
l
i
,
r
i
l_i,r_i
li,ri,满足
∀
i
≠
j
,
[
l
i
,
r
i
]
∩
[
l
j
,
r
j
]
\forall i\neq j ,[l_i,r_i] \cap [l_j,r_j]
∀i=j,[li,ri]∩[lj,rj]是一个端点或空,且
∀
i
∈
[
1
,
n
]
f
i
(
r
i
)
−
f
i
(
l
i
)
≥
L
n
\forall i\in [1,n] f_{i}(r_i) - f_i(l_i) \geq \frac Ln
∀i∈[1,n]fi(ri)−fi(li)≥nL。
题解:
考虑一个分治算法:
对所有函数都求出
x
i
x_i
xi使得
f
i
(
x
i
)
=
L
2
f_i(x_i) = \frac L2
fi(xi)=2L,
那么按
x
i
x_i
xi排序后,前一半和后一半就可以递归下去,取值范围从
[
0
,
1
e
18
]
[0,1e18]
[0,1e18]变成了
[
0
,
x
n
2
]
[0,x_{\frac n2}]
[0,x2n]和
[
x
n
2
,
1
e
18
]
[x_{\frac n2},1e18]
[x2n,1e18]。
求出
x
i
x_i
xi的操作数复杂度是
O
(
log
1
e
18
)
O(\log 1e18)
O(log1e18)
所以总操作数是
O
(
n
log
1
e
18
log
n
)
O(n \log 1e18 \log n)
O(nlog1e18logn)
考虑用其他方法求出
x
n
2
x_{\frac n2}
x2n。
随机一个函数
f
k
(
x
)
f_k(x)
fk(x),求出
x
k
x_k
xk使得
f
k
(
x
k
)
=
L
2
f_k(x_k) = \frac L2
fk(xk)=2L
对于其他函数求出
f
i
(
x
k
)
f_i(x_k)
fi(xk),如果
f
i
(
x
k
)
<
f
k
(
x
k
)
f_i(x_k) < f_k(x_k)
fi(xk)<fk(xk)的大于了
n
2
\frac n2
2n,
那么说明
f
k
f_k
fk肯定不是中位函数,中位函数在
f
i
(
x
k
)
<
f
k
(
x
k
)
f_i(x_k) < f_k(x_k)
fi(xk)<fk(xk)的
f
i
f_i
fi中。
然后递归缩小范围后再随机函数再算。
期望递归
O
(
log
n
)
O(\log n)
O(logn)次。
所以对于大小为
n
n
n的一层的复杂度为
O
(
n
log
1
e
18
log
n
+
n
)
O(n\log 1e18 \log n + n)
O(nlog1e18logn+n)
求个和
∑
i
=
1
10
2
10
−
i
log
1
e
18
i
+
2
i
\sum_{i=1}^{10} 2^{10-i} \log 1e18 i + 2^i
∑i=110210−ilog1e18i+2i
=
log
1
e
18
n
+
n
log
n
= \log 1e18 n + n\log n
=log1e18n+nlogn
需要卡卡常。
需要调到疯
A
C
C
o
d
e
\mathcal AC \ Code
AC Code
#include<bits/stdc++.h>
#define LL long long
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
#define maxn 1005
int n;LL L,al[maxn],ar[maxn];
int arr[maxn][maxn]={
{}
,{0,0,1,1,2,3,4,4}
,{0,1,1,2,2,3,3,4}
,{0,1,2,2,2,3,3,4}
,{0,0,0,0,1,2,3,4}
};
LL getv(int u,LL v){
printf("? %d %lld\n",u,v);
fflush(stdout);
LL r;
scanf("%lld",&r);
return r/* = arr[u][v]*/;
}
LL ser(int u,LL v,LL l,LL r){
LL m;
for(;l<r;){
m = l+r>>1;
LL t = getv(u,m);
if(t < v) l = m + 1;
else if(t > v) r = m - 1;
else return m;
}
return l;
}
int vis[maxn],tim;
LL llc;
void qry(vector<int>&g,vector<int>&p,LL ql,LL qr,LL aim,int ls){
int t = g[rand() % g.size()];
LL x = ser(t,aim,ql,qr);
vector<int>l,r,z;
rep(i,0,p.size()-1) if(p[i] != t){
LL y = getv(p[i],x);
if(y == aim) z.push_back(p[i]);
if(y < aim) l.push_back(p[i]);
if(y > aim) r.push_back(p[i]);
}
for(;l.size() < ls && !z.empty();)
l.push_back(z.back()),z.pop_back();
for(;!z.empty();)
r.push_back(z.back()),z.pop_back();
if(l.size() <= ls && r.size() < p.size()-ls){
g.clear();
g.push_back(t);
llc = x;
return;
}
// printf("@%d %d %d\n",l.size(),r.size(),t);
if(l.size() > ls){
++tim;
rep(i,0,l.size()-1) vis[l[i]] = tim;
for(int i=0;i<g.size();i++) if(vis[g[i]] != tim)
swap(g[i],g.back()),g.pop_back(),i--;
qry(g,p,ql,qr,aim,ls);
}
else{
++tim;
rep(i,0,r.size()-1) vis[r[i]] = tim;
for(int i=0;i<g.size();i++) if(vis[g[i]] != tim)
swap(g[i],g.back()),g.pop_back(),i--;
qry(g,p,ql,qr,aim,ls);
}
}
void Solve(vector<int>&p,LL ql,LL qr,LL pl,LL pr){
// printf("@%d %lld %lld %lld %lld\n",p.size(),ql,qr,pl,pr);
// rep(i,0,p.size()-1) printf("%d%c",p[i]," \n"[i==p.size()-1]);
if(p.empty()) return;
if(p.size() == 1){
al[p[0]] = ql , ar[p[0]] = qr;
return;
}
vector<int>g = p;
int m = p.size() / 2;
qry(g,p,ql,qr,pl + (pr-pl) / p.size() * m,m);
int t = g[0];
// printf("##%d %lld\n",t,llc);
vector<int>l,r,z;
rep(i,0,p.size()-1){
LL y = getv(p[i],llc);
if(y == pl + (pr-pl) / p.size() * m) z.push_back(p[i]);
if(y > pl + (pr-pl) / p.size() * m) l.push_back(p[i]);
if(y < pl + (pr-pl) / p.size() * m) r.push_back(p[i]);
}
for(;l.size() < m;)
l.push_back(z.back()),z.pop_back();
for(;!z.empty();)
r.push_back(z.back()),z.pop_back();
LL tmp = llc;
Solve(l,ql,tmp,pl,pl + (pr-pl) / p.size() * m);
Solve(r,tmp,qr,pl + (pr-pl) / p.size() * m,pr);
}
int main(){
scanf("%d%lld",&n,&L);
vector<int>p;
rep(i,1,n) p.push_back(i);
Solve(p,0,1e18,0,L);
puts("!");
rep(i,1,n) printf("%lld %lld\n",al[i],ar[i]);
}