[luogu7207]Sob

为了方便,先将$n$减小1,即两者范围分别为$[0,n]$和$[m,m+n]$

结论:取$u=min_{iin [m,m+n],n& i=n}i$,则$forall 0le ile u-m,(n-i)&(u-i)=n-i$

证明分为两点:1.$u$的存在性;2.后者成立

关于$u$的存在性(题目描述中已经保证),取$2^{k-1}le n<2^{k}$且$n$二进制下即恰有$k$位(无前导0),并再假设这$k$位中有$t$个0,显然$nge 2^{k}-2^{t}$(即最低的$t$位为0)

再考虑任意连续$2^{k}$个非负整数中,总存在$2^{t}$个数$i$满足$n& i=n$(这些数最低的$k$位恰包含所有情况),进而对于任意连续$n+1$个数,即至多去掉了$2^{t}-1$个数,必然留下一个数$i$满足$n& i=n$

关于后者,取最小的$k$满足$u$在二进制下第$k$位为1而$n$为0,假设$u$在二进制下最低的$k-1$位的值为$u'$,那么当$ile u'$时有$(n-i)&(u-i)=n-i$(仅有最低的$k-1$位发生变化,而两者这$k-1$位完全相同)

因此,结论不成立的必要条件为$u'+1le u-m$,此时考虑$u-(u'+1)$,其也满足$u$的性质且更小,那么即与$u$的最小性矛盾

由此,将这些依次匹配后,即从$(n,m)$变为$(n-(u-m)-1,u+1)$的子问题,重复此过程即可

注意到每一次找到$u$过程中的数都会被匹配,因此暴力找$u$即可

时间复杂度为$o(n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m;
 4 void calc(int n,int m){
 5     for(int i=m;i<=m+n;i++)
 6         if ((n&i)==n){
 7             for(int j=0;j<=i-m;j++)printf("%d %d
",n-j,i-j);
 8             calc(n-(i-m)-1,i+1);
 9             break;
10         }
11 }
12 int main(){
13     scanf("%d%d",&n,&m);
14     calc(n-1,m);
15     return 0;
16 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/15393881.html