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

Problem Description

Given a directed graph with nn nodes, labeled 0,1,⋯,n−1.

For each <i, j> satisfies 0≤i<j<n, there exists an edge from the i-th node to the j-th node, the capacity of which is i xor j.

Find the maximum flow network from the 0-th node to the (n-1)-th node, modulo 1000000007.

Input

Multiple test cases (no more than 10000).

In each test case, one integer in a line denotes n(2≤n≤10^18 ).

Output

Output the maximum flow modulo 11000000007 for each test case.

​​​​​​​Sample Input

2

​​​​​​​Sample Output

1

题意:多组数据,每组给出一个数 n,代表有 n 个编号从 0 到 n-1 的点,现在对于这 n 个点,当 i<j 时,两点之间存在一条边,其边容量为 i^j,问从 0 到 n-1 的最大流

思路:

多画几组样例可以发现,0 到 n-1 两点之间必须要割

对于任意一个 i,0 到 i 与 i 到 n−1 至少要割一个,因此考虑 i 在 n−1 的最高位是否为 0 即可,若最高位为 0 就割 0 到 i,否则就割 i 到 n−1

在图中经过这样的割后,一定存在一个分界线 100...00,使得前面所有的点与 n-1 连通不与 0 连通,后面所有的点与 0 连通不与 n-1 连通,这样 0 与 n-1 就隔开了

于是问题就转换成了求割下来的各条边的流量和,从 i 个最高位考虑:

若 i 的最高位为 0 时,割为 0 到 i,其流量和就是 1+2+...+(2^(len-1)-1)

当 i 的最高位为 1 时,割为 i 到 n−1,考虑从低位向高位找 n−1 中除最高位外为 1 的位,设当前为第 j 位,那么可对从最高位到第 j+1 位与 n-1 相同且第 j 位为 0 的数求和

对于这些数,j-1 位到 0 位于 n-1 的异或值就是 1+2+...+(2^(j-1)-1),第 j 位与 n-1 的异或值为 2^j,最高位到第 j+1 位与 n-1 的异或值为 0

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL quickModPow(LL a,LL b,LL mod){ LL res=1; a=a%mod; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1;} return res; }
LL getInv(LL a,LL mod){ return quickModPow(a,mod-2,mod); } // (a/b)%MOD=(a%MOD * getInv(b)%MOD)%MOD
const double EPS = 1E-10;
const int MOD = 1E9+7;
const int N = 100000+5;
const int dx[] = {-1,1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;

int main() {
    LL n;
    while(scanf("%lld",&n)!=EOF){
        if(n==2)
            printf("1\n");
        else{
            n--;

            LL temp=n;
            int len=0;
            while(temp){
                len++;
                temp/=2;
            }

            LL temp1=quickModPow(2,len-2,MOD);
            LL temp2=(quickModPow(2,len-1,MOD)-1+MOD)%MOD;
            LL res=(temp1%MOD*temp2%MOD)%MOD;
            res=(res+n)%MOD;

            for(int i=0; i<len-1; i++) {
                if(n&(1LL<<i)) {//最高位为1时
                    if (i==0)
                        res=(res+1)%MOD;
                    else{
                        temp1=((3LL<<i)%MOD-1+MOD)%MOD;
                        temp2=quickModPow(2,i-1,MOD);
                        res=(res+(temp1*temp2)%MOD)%MOD;
                    }
                }
            }
            printf("%lld\n", res);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值