博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj4842 Delight for a Cat
阅读量:6239 次
发布时间:2019-06-22

本文共 3974 字,大约阅读时间需要 13 分钟。

题意:n天内你每天可以s或者e,分别有一定的收益。

每连续k天中s的天数要大于ds,e的天数要大于de,求最大收益。

解:费用流解线性规划。

先假设全部选e,然后一天s的收益为si - ei

ai表示第i天是否s,up = k - de, down = ds, R = up - down,有:

两两做差:

最后两个式子是人为补全的,这样就满足:每个变量在等号左边和右边各出现一次。

把每个等号看做点,每个值看做一条边。

常数项就连向源汇。

y和z代表的边啥都不需要限制,a要限流为1,费用为si - ei,然后求最大费用最大流即可。

输出方案:看改变量代表的边是否有流量即可。

1 #include 
2 #include
3 #include
4 #include
5 6 typedef long long LL; 7 const int N = 5050, M = 1000010; 8 const LL INF = 0x3f3f3f3f3f3f3f3f; 9 10 struct Edge { 11 int nex, v; 12 LL c, len; 13 }edge[M << 1]; int top = 1; 14 15 int e[N], vis[N], pre[N]; 16 LL d[N], flow[N]; 17 std::queue
Q; 18 LL vs[N], ve[N]; 19 20 inline void add(int x, int y, LL z, LL w) { 21 top++; 22 edge[top].v = y; 23 edge[top].c = z; 24 edge[top].len = w; 25 edge[top].nex = e[x]; 26 e[x] = top; 27 28 top++; 29 edge[top].v = x; 30 edge[top].c = 0; 31 edge[top].len = -w; 32 edge[top].nex = e[y]; 33 e[y] = top; 34 return; 35 } 36 37 inline bool SPFA(int s, int t) { 38 memset(d, 0x3f, sizeof(d)); 39 d[s] = 0; 40 flow[s] = INF; 41 vis[s] = 1; 42 Q.push(s); 43 while(!Q.empty()) { 44 int x = Q.front(); 45 Q.pop(); 46 vis[x] = 0; 47 for(int i = e[x]; i; i = edge[i].nex) { 48 int y = edge[i].v; 49 if(edge[i].c && d[y] > d[x] + edge[i].len) { 50 d[y] = d[x] + edge[i].len; 51 pre[y] = i; 52 flow[y] = std::min(flow[x], edge[i].c); 53 if(!vis[y]) { 54 vis[y] = 1; 55 Q.push(y); 56 } 57 } 58 } 59 } 60 return d[t] < INF; 61 } 62 63 inline void update(int s, int t) { 64 LL temp = flow[t]; 65 while(t != s) { 66 int i = pre[t]; 67 edge[i].c -= temp; 68 edge[i ^ 1].c += temp; 69 t = edge[i ^ 1].v; 70 } 71 return; 72 } 73 74 inline LL solve(int s, int t, LL &cost) { 75 LL ans = 0; 76 cost = 0; 77 while(SPFA(s, t)) { 78 ans += flow[t]; 79 cost += flow[t] * d[t]; 80 update(s, t); 81 } 82 return ans; 83 } 84 85 int main() { 86 int n, k, ds, de; 87 LL sum = 0; 88 scanf("%d%d%d%d", &n, &k, &ds, &de); 89 for(int i = 1; i <= n; i++) { 90 scanf("%lld", &vs[i]); 91 } 92 for(int i = 1; i <= n; i++) { 93 scanf("%lld", &ve[i]); 94 sum += ve[i]; 95 vs[i] -= ve[i]; 96 } 97 int up = k - de, down = ds, lm = n - k + 1; 98 int s = N - 1, t = N - 2; 99 for(int i = 1; i <= n - k + 1; i++) {100 if(i == 1) { // yi101 add(i, lm * 2 + 1, INF, 0ll);102 }103 else {104 add(i, lm + i - 1, INF, 0ll);105 }106 if(i == n - k + 1) { // zi107 add(i, lm * 2 + 2, INF, 0ll);108 }109 else {110 add(i, lm + i, INF, 0ll);111 }112 }113 int OP = top;114 for(int i = 1; i <= n; i++) {115 // ai116 int ss = lm + i, tt = i - k + lm;117 if(i <= k) {118 tt = lm * 2 + 1;119 }120 if(i >= n - k + 1) {121 ss = lm * 2 + 2;122 }123 add(ss, tt, 1ll, -vs[i]);124 }125 int ED = top;126 for(int i = 1; i <= n - k + 1; i++) {127 add(s, i, up - down, 0ll);128 add(i + lm, t, up - down, 0ll);129 }130 add(lm * 2 + 1, t, up, 0ll);131 add(s, lm * 2 + 2, down, 0ll);132 133 LL ans;134 solve(s, t, ans);135 printf("%lld\n", sum - ans);136 for(int i = OP + 1; i <= ED; i += 2) {137 if(edge[i].c) {138 putchar('E');139 }140 else {141 putchar('S');142 }143 }144 return 0;145 }
AC代码

 

转载于:https://www.cnblogs.com/huyufeifei/p/10115654.html

你可能感兴趣的文章
OPEN SSH升级小结(针对SUSE REDHAT linux系统)
查看>>
Myeclipse优化配置
查看>>
RabbitMQ学习总结(7)——Spring整合RabbitMQ实例
查看>>
Notepad++ 快捷键大全
查看>>
Oracle统计求和
查看>>
在Android搭建简单的服务器
查看>>
智能合约编程/Dapp漏洞 --Unexpected Ether
查看>>
perl写的tcp连接数
查看>>
Windows 7自带截图工具技巧两则
查看>>
如何规划构建一套大型的Citrix桌面虚拟化架构 - 后记
查看>>
zencart lazyload插件
查看>>
delete和delete[] 的深度思考
查看>>
linux ifconfig命令
查看>>
截杀“WannaCrypt”,终结“永恒之蓝”!
查看>>
Oracle内部视图:x$ktfbue
查看>>
【日常管理】Asm Diskgroup增加磁盘add disk
查看>>
Exadata下新建DiskGroup
查看>>
了解ocssd.bin如何控制RAC节点重启
查看>>
CentOS学习笔记 - 8. docker 编译基于gofabric8的java应用镜像
查看>>
关于ps cs6的滤镜 (抽出)
查看>>