Given a directed graph with n 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 Format
Multiple test cases (no more than 10000).
In each test case, one integer in a line denotes n(2≤n≤1018).
Output Format
Output the maximum flow modulo 1000000007 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);
}
}