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

题目链接

题意

n 个点,0,1,2,...,n1,对于没对点 <i,j>(0i<j<n) <script type="math/tex" id="MathJax-Element-212"> (0\leq i\lt j\lt n)</script>,有一条 ij 边,流量为 i Xor j ,问从 0 n1 的最大流。

思路

首先, 0 n1 必须要割;

其次,对于任意一个 i 0i in1 至少要割一个。考虑 i n1 的最高位是否为 0 ,如果为 0,就割 0i ,否则割 in1 .

这样割,肯定有一个点为分界线( 1000 ),前面的所有点与 n1 连通而不与 0 连通,后面的所有点与 0 连通而不与 n1 连通,于是 0 n1 就割开了。

现在的问题就是怎么求割下来的各条边的流量和。

i 的最高位为 0 时,割 0i ,就是 1+2+3+...+((1<<(len1))1) .

i 的最高位为 1 时,割 in1 ,考虑从低位往高位去找 n1 中为 1 的位(除了最高位),不妨设当前为第 j 位,则可以对从最高位到第 j+1 位都与 n1 相同,而第 j 位为 0的数求和。
对于这些数,其 j1 0 位与 n1 的异或值就是 1+2+3+...+((1<<j)1) ;第 j 位与 n1 的异或值是 1<<j ;最高位到第 j+1 n1 的异或值为 0 <script type="math/tex" id="MathJax-Element-7424">0</script>.

Code

#include <bits/stdc++.h>
typedef long long LL;
const LL mod = 1e9+7;
LL n;
void work() {
    if (n == 2) { printf("1\n"); return;}
    --n;
    int len = 0;
    LL nn = n;
    while (nn) ++len, nn >>= 1;
    LL ans = (1LL << (len-2)) % mod * (((1LL << (len-1)) - 1 + mod) % mod) % mod;
    (ans += n) %= mod;
    for (int i = 0; i < len-1; ++i) {
        if (n & (1LL << i)) {
            if (i == 0) (ans += 1) %= mod;
            else (ans += (((3LL << i) % mod - 1 + mod) % mod * ((1LL << (i-1)) % mod)) % mod) %= mod;
        }
    }
    printf("%lld\n", ans);
}
int main() {
    while (scanf("%lld", &n) != EOF) work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值