原题链接:https://nanti.jisuanke.com/t/17118
题目大意:有一个网络流的图,点的标号为从0到N-1,点i , j( i<j)之间存在一条从i到 j 的容量为 i xor j 的有向边,
问从0到N-1的最大流是多少。
假设2^k<=N-1<x^(k+1),则对于 0<=i<=2^k-1,点0到点i的流量小于2^k,而点i到点N-1的边的容量不小于2^k,所以这些点到N-1的总流量就是i
对于2^k<= i <= N-1 ,这些点到点N-1的边的容量不大于2^k,而点0到点i的流量不小于2^k,所以点i到N-1的总流量就是(N-1) xor i 。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
inline void read(long long &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
inline void write(int x){
static const int maxlen=100;
static char s[maxlen];
if (x<0) { putchar('-'); x=-x;}
if(!x){ putchar('0'); return; }
int len=0; for(;x;x/=10) s[len++]=x % 10+'0';
for(int i=len-1;i>=0;--i) putchar(s[i]);
}
const long long P=1000000007ll;
const long long ny2=500000004ll;
long long n;
long long get_num(long long x){
if (x==0)
return 0;
long long kk=1;
while ( kk<x)
kk=kk*2;
if ( kk>x)
kk=kk/2;
return ( ( ( ( (kk-1)%P) *(kk%P)%P ) *( ny2%P)%P )%P+ (kk%P)*( kk%P)%P + get_num(x-kk)%P )%P;
}
long long get_ans(long long x){
if (x==0)
return 0;
long long kk=1;
while ( kk<x)
kk=kk*2ll;
if ( kk>x)
kk=kk/2ll;
long long T=get_num(x-kk)%P;
return ( ( ( ( ( (kk-1)%P ) * ( kk%P ) )%P )*( ny2%P )%P )%P +T%P+x%P )%P;
}
int main(){
while ( scanf("%lld",&n)!=EOF)
cout<<get_ans(n-1)<<endl;
return 0;
}