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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值