我是靠谱客的博主 甜美钥匙,这篇文章主要介绍2017 ACM-ICPC 亚洲区域赛【西安站网赛】Maximum Flow,现在分享给大家,希望可以做个参考。

一道很神奇的题

送上计蒜客传送门:https://nanti.jisuanke.com/t/17118

题目大意:
1018 个点的图,他们两两之间有一条边,边的流量是i ^ j。
现在问。从0点出发到n - 1点,最大流是多少。

吐槽:
比赛的时候,找网络流队友暴力打了前1000个数出来,竟然发现了规律。。然后硬生生怼了个log(n)的 倍减算法。
然后直到比赛结束之后。。都算不清楚他的数orz(以后再也不推公式了)。
题目真的套路啊,写了个最大流。结果是数位dp。。还能推公式

思维不是很懂,队友提供的,说要将高位是1的,都跟n - 1连。
高位是0的,都跟0连,连完之后 j1+n1j+1jxor(n1) 就是最大流的答案
但是这n是 1018 ,太大了,明显可以数位dp一下。
将n - 1转成2进制,dp[i][j][k] 代表,到第i位时,最高位是j的方案数,k代表是否是上限。
fp表示他们的和。
然后数位dp一下就好了。
感谢qls提供的代码思路orz

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* @resources: regional @date: 2017-09-17 @author: QuanQqqqq @algorithm: 网络流思想 数位dp */ #include <bits/stdc++.h> #define ll long long #define MOD 1000000007 using namespace std; ll dp[65][2][2], fp[65][2][2]; ll bits[65]; void add(ll &a, ll b) { a += b; if (a > MOD) { a -= MOD; } } ll solve(ll n) { ll ret = n % MOD; memset(dp, 0, sizeof(dp)); memset(fp, 0, sizeof(fp)); int cnt = 0; while (n) { bits[++cnt] = n % 2; n /= 2; } reverse(bits + 1, bits + cnt + 1); dp[1][0][0] = dp[1][1][1] = 1; for (int i = 2; i <= cnt; i++) { for (int j = 0; j < 2; j++) { //最高位 for (int k = 0; k < 2; k++) { //是否满数 for (int l = 0; l < 2; l++) { //当前位置 if (k == 1 && l > bits[i]) { continue; } int ks = k == 1 && l == bits[i]; int tc = l ^ (j == 1 ? bits[i] : 0); add(dp[i][j][ks], dp[i - 1][j][k]); add(fp[i][j][ks], (2LL * fp[i - 1][j][k] + 1LL * tc * dp[i - 1][j][k]) % MOD); } } } } for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { add(ret, fp[cnt][i][j]); } } return ret; } int main(){ ll n; while (~scanf("%lld", &n)) { printf("%lldn", solve(n - 1)); } }

最后

以上就是甜美钥匙最近收集整理的关于2017 ACM-ICPC 亚洲区域赛【西安站网赛】Maximum Flow的全部内容,更多相关2017内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(78)

评论列表共有 0 条评论

立即
投稿
返回
顶部