[BZOJ 3996] [TJOI 2015] 线性代数

3996: [TJOI2015]线性代数

Time Limit: 10 SecMemory Limit: 128 MB

Description

给出一个N*N的矩阵B和一个1*N的矩阵C。求出一个1*N的01矩阵A.使得

D=(A*B-C)*A^T最大。其中A^T为A的转置。输出D

Input

第一行输入一个整数N,接下来N行输入B矩阵,第i行第J个数字代表Bij.

接下来一行输入N个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不超过1000的非负整数。

Output

输出最大的D

Sample Input

3
1 2 1
3 1 0
1 2 3
2 3 7

Sample Output

2

HINT

1<=N<=500

【题解】

花了好久时间化简,最后化简出来是

我们发现,a是一个01矩阵,然后其实就可以化成这么一个问题:

有n个东西,选了i,j两件东西能得到b[i,j]的价值,然而选i需要c[i]的花费,选j需要c[j]的花费……

据大聚聚们说,这是一个经典的最小割模型。

建立S,T。

S连(i,j)边,边权为b[i,j],(i,j)连i、连j边,边权均为∞,i向T连边,边权为c[i]。

然后求最小割,最后答案就是

sum(b[i][j])-最小割答案  (i∈[1..n],j∈[1..n])

最小割今天早上刚写过dinic哈哈=-=

然而第一次写边链表,好在也AC了

STL的queue被卡RE了 TAT好可怕要自己写队列了

然后了一堆地方有bug调了一个小时

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #include<algorithm>
 6 #include<math.h>
 7 #include<string>
 8 using namespace std;
 9 const int inf=210000;
10 int c[250510],head[250510];
11 long long ans;
12 int q[250510];
13 int s,t,n,tt,heads,tail;
14 struct edge {
15     int next,num,x;
16 }e[2505010];
17 int read2() {
18     int x=0; int f=1;
19     char ch=getchar();
20     while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-1; ch=getchar();}
21     while(ch>=‘0‘&&ch<=‘9‘) {x=(x<<3)+(x<<1)+ch-‘0‘; ch=getchar();}
22     return x*f;
23 }
24 inline void f(int a,int b,int w) {
25     e[++tt].next=head[a];head[a]=tt;
26     e[tt].num=w;e[tt].x=b;
27     e[++tt].next=head[b];head[b]=tt;
28     e[tt].num=0;e[tt].x=a;
29 }
30 bool bfs() {
31     for (int i=s;i<=t;++i) c[i]=0;
32     heads=tail=1;
33     q[tail]=s;c[s]=1;
34     while(heads<=tail) {
35         int top=q[heads++];
36         for (int i=head[top];i;i=e[i].next) {
37             int x=e[i].x,num=e[i].num;
38             if(num==0||c[x]>0) continue;
39             c[x]=c[top]+1;
40             q[++tail]=x;
41             if(x==t) return 1;
42         }
43     }
44     return 0;
45 }
46 int dfs(int y,int low) {
47     if(y==t) return low;
48     int flow,r=low;
49     for (int i=head[y];i;i=e[i].next) {
50         int x=e[i].x,num=e[i].num;
51         if(c[x]!=c[y]+1 || num==0) continue;
52         flow=dfs(x,min(r,num));
53         r-=flow;
54         e[i].num-=flow; e[i^1].num+=flow;
55         if(!r) return low;
56     }
57     if(r==low) c[y]=-1;
58     return low-r;
59 }
60 int main() {
61     //freopen("algebra.in","r",stdin);
62     //freopen("algebra.out","w",stdout);
63     int k,w;
64     n=read2();s=0,t=n*n+n+1; k=n;
65     for (int i=1;i<=n;++i)
66         for (int j=1;j<=n;++j) {
67             w=read2();
68             ans+=w;
69             f(s,++k,w);
70             f(k,i,inf);
71             f(k,j,inf);
72         }
73     for (int i=1;i<=n;++i) {
74         w=read2();
75         f(i,t,w);
76     }
77     while(bfs()) ans-=dfs(s,inf);
78     cout<<ans<<endl;
79     //fclose(stdin);
80     //fclose(stdout);
81     return 0;
82 }

 这是我在BZOJ AC的第10题,仅此纪念  2015/6/12

时间: 2024-10-11 16:42:13

[BZOJ 3996] [TJOI 2015] 线性代数的相关文章

BZOJ 3996 [TJOI 2015] 线性代数 解题报告

首先,我们可以得到: $$D = \sum_{i=1}^{n}\sum_{j=1}^{n}a_i\times a_j\times b_{i,j} - \sum_{i=1}^{n}a_i\times c_i$$ 那么是不是就相当于这样的问题: 有 $n$ 个物品,你可以选择一些物品出来,如果同时选了 $i,j$ 两个物品那么就有 $b_{i,j}$ 的收益,然而每一个物品都有一个代价 $c_i$,求最大收益. 这是经典的最小割模型: 连边 $S\to Dot(i,j)$,流量为 $b_{i,j}$

[BZOJ 4001] [TJOI 2015] 概率论

4001: [TJOI2015]概率论 Time Limit: 10 SecMemory Limit: 128 MB Description Input 输入一个正整数N,代表有根树的结点数 Output 输出这棵树期望的叶子节点数.要求误差小于1e-9 Sample Input 1 Sample Output 1.000000000 HINT 1<=N<=10^9 Source [题解]拍个暴力,算算前5个,推了下公式,大概就是f(n)=n(n+1)/2/(2n-1) 然后就AC了=-= 1

BZOJ 3997 [TJOI 2015 组合数学] 解题报告

这个题我脑洞了一个结论: 首先,我们定义满足以下条件的路径为“从右上到左下的路径”: 对于路径上任何不相同的两个点 $(x_1, y_1)$,$(x_2, y_2)$,都有: $x_1\neq x_2, y_1\neq y_2$ 若 $x_1 > x_2$,则有 $y_1 < y_2$:否则当 $x_1 < x_2$ 时, $y_1 > y_2$. 然后我们找到所有从右上到左下的路径,其中路径的权值和最大的那条路径的权值和就是答案了. 然后我们就可以用 Dp 解决问题了. 我们可以

[BZOJ 3997] [TJOI 2015] 组合数学

3997: [TJOI2015]组合数学 Time Limit: 20 SecMemory Limit: 128 MB Description 给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走.问至少走多少次才能将财宝捡完.此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完. Input 第一行为正整数T,代表数据组数. 每组数据第一行为正整数N,M代表网格图有N行M列,接下来N行每行M个非负整数,表示此格子中财

[TJOI 2015] 线性代数

题目传送-Luogu3973 题意: 给定一个\(n×n\)的矩阵\(B\)和一个\(1×n\)的矩阵\(C\),求一个\(1×n\)的\(01\)矩阵\(A\).使得\(D=(A×B-C)×A^{\sf T}\)最大,其中\(A^{\sf T}\)为\(A\)的转置.输出\(D\). \(n \le 500,1 \le Allelement \le 1000\) 题解: emmm这是道网络流..二十多万条边跑网络流也是有信仰的了 脑补一下我们可以发现以下性质: 只有当\(a_i=1\)且\(a

bzoj 3996 线性代数 —— 最大权闭合子图

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3996 把题中的式子拆开看看,发现就是如下关系: 如果 a[i] == 1 && a[j] == 1,则 b[i][j] 有贡献: 如果 a[i] == 1,则 -c[i] 有贡献: 所以就是最大权闭合子图的模型,b[i][j] 向 a[i] 和 a[j] 连边,a[i] 向 c[i] 连边: 而 c[i] 这个点实际上没什么用,直接变成 a[i] 向 T 连边,边权是 c[i] 即可

BZOJ 3170: [Tjoi 2013]松鼠聚会( sort )

题目的距离为max(|x1-x2|, |y1-y2|) (切比雪夫距离). 切比雪夫距离(x, y)->曼哈顿距离((x+y)/2, (x-y)/2) (曼哈顿(x, y)->切比雪夫(x+y, x-y)). 转成Manhattan distance后排序前缀和维护即可. -------------------------------------------------------------------------- #include<cstdio> #include<cs

[BZOJ 3747] [POI 2015] Kinoman【线段树】

Problem Link : BZOJ 3747 题解:ZYF-ZYF 神犇的题解 解题的大致思路是,当区间的右端点向右移动一格时,只有两个区间的左端点对应的答案发生了变化. 从 f[i] + 1 到 i 的区间中的答案增加了 W[A[i]], 从 f[f[i]] + 1 到 f[i] 的区间的答案减少了 W[A[i]] ,其余区间的答案没有发生变化. 那么就是线段树的区间修改和区间最值查询. 代码如下: #include <iostream> #include <cstdio>

bzoj 4199 &amp;&amp; NOI 2015 品酒大会

一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手"两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒.这 nn 杯鸡尾酒排成一行,其中第 ii 杯酒 (1≤i≤n1≤i≤n) 被贴上了一个标签 sisi,每个标签都是 2626 个小写英文字母之一.设 Str(l,r)Str(l,r) 表示第 ll 杯酒到第 rr 杯酒的 r?l+1