2017 ACM-ICPC 亚洲区(西安赛区)网络赛 Maximum Flow

原题链接: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;
}


猜你喜欢

转载自blog.csdn.net/u012602144/article/details/78005190