【2017西安网络赛】E Maximum Flow

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

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

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

Input Format

Multiple test cases (no more than 1000010000).

In each test case, one integer in a line denotes n(2≤n≤1018)n(2n1018).

Output Format

Output the maximum flow modulo 10000000071000000007 for each test case.

样例输入
2
样例输出
1

题意:

现在有n个点,编号为0至n-1, 满足i<j的任意两点连一条i^j流量的边,问0到n-1的最大流。 n<=1e18


思路:
比赛搞了4小时这题,最后才过,,,发现大家居然是找规律过的。。。

首先从0到n流量一定是n,
从0到n-1,再从n-1到n,分为两种情况。
一种是(n^(n-1))>n-1,这种情况下都是流量赛n-1,而之后的也都是满流。
另一种情况(n^(n-1))<=n-1,分为两个部分,我们将n看成二进制形式,从0开始出发的流量大小为1到n。从1到2^k-1(2^k<=n)一定是满流的,直接求和。而从2^k到n-1的流量等于n分别与它们的异或后的和。
举个例子:从0到6:
110 满流 =6
101 =110^101 = 3 
100 =110^100 = 2
011 满流 =3
010 满流 =2
001  满流 =1
加起来后等于 17.

还需要解决的一个问题是怎么快速求n^(n-1)+n^(n-2)+...+n^(2的k次方),这个问题可以退化成怎么求n^(n-1)+n^(n-2)+...+n^0。
再举个例子,n=9
n的二进制1001。
我们先计算(0001+0010+...+1111)也就是(1+2+...+15) =120
从右往左扫,发现第二位为0,则减去(10+11) =5
第三位为0,则减去(100+101+110+111)=22
结果等于120-5-22=93。


居然是全场题,不开心。
//
//  main.cpp
//  E
//
//  Created by zc on 2017/9/16.
//  Copyright © 2017年 zc. All rights reserved.
//

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;

const ll MOD=1e9+7;
ll n,a[66];

int main(int argc, const char * argv[]) {
    /*for(int i=2;i<=1000;i++)
    {
        ll ans=(ll)i-1;
        for(int j=i-2;j>=1;j--)
        {
            ans=(ans+min(j,(i-1)^j))%MOD;
        }
        printf("%lld,",ans);
    }*/
    a[0]=1;
    for(int i=1;i<63;i++)   a[i]=(a[i-1]*2);
    while(~scanf("%lld",&n))
    {
        n--;
        ll ans;
        if((n^(n-1))>n-1)
        {
            if(n%2==0)  ans=(((n/2)%MOD)*((n+1)%MOD))%MOD;
            else    ans=((n%MOD)*(((n+1)/2)%MOD))%MOD;
        }
        else
        {
            ll sum=1;
            for(int i=0;i<63&&sum<=n;i++)
            {
                sum<<=1;
            }
            sum>>=1;
            ans=n%MOD;
            ll q=n-sum;
            ll tsum=1;
            for(int i=0;i<63&&tsum<=q;i++)
            {
                tsum<<=1;
            }tsum--;
            ll tans=((((1+tsum)/2)%MOD)*((tsum)%MOD))%MOD;
            ll tt=1;
            for(int i=0;i<63&&q;i++)
            {
                ll tq=(((a[i]+a[i+1]-1)%MOD)*((a[i]/2)%MOD))%MOD;
                if(i==0)    tq=1;
                if(!(q&1)) tans=(tans+MOD-tq)%MOD;
                q>>=1;
            }
            ans=(ans+tans+MOD)%MOD;
            ll t=sum-1;
            if(t%2==0)  ans=(ans+((t/2)%MOD)*((t+1)%MOD))%MOD;
            else    ans=(ans+(t%MOD)*(((t+1)/2)%MOD))%MOD;
        }
        printf("%lld\n",ans);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值