【BZOJ】【TJOI2015】线性代数
2015-05-22 21:38
183 查看
网络流/最小割/最大权闭合图
2333好开心,除了一开始把$500^2$算成25000……导致数组没开够RE了一发,可以算是一次AC~咳咳还是回归正题来说题解吧:
一拿到这道题,我就想:这是什么鬼玩意……矩阵乘法早忘了……画了半天也想不起来到底是谁乘谁,只记得有个式子:$c[i][j]=\sum a[i][k]*b[k][j]$
好吧没关系,既然画图不行了,我们就先拿这个东西,纯代数来搞!
D的表达式,里面那层我们可以写成:$\sum a[i][k]*b[k][j] - c[i][j]$
然而a和c都是1*N的矩阵,简化一下,我们得到:$$ \sum a[k]*b[k][j]-c[j]$$
所以我们把D的表达式转化一下,发现可以把c[j]提出来:$$ \begin{aligned} D&=\sum_{j=1}^n \big ( \sum_{k=1}^n a[k]*b[k][j]-c[j] \big )*a[j] \\ &=\sum_{j=1}^n \sum_{k=1}^n a[j]*a[k]*b[k][j]-\sum_{k=1}^n a[j]*c[j] \end{aligned} $$
这时我们发现:b[j][k]和c[j]前面分别乘了一或两个0/1变量……感觉像什么……最大权闭合图对不对……同时选了 j 和 k 的话可以得到b[j][k]的收益,但是选 j 得付出c[j]的代价!
这时候我们就可以轻松+愉快的进行建图……
好久没写过网络流了,一次写对Dinic还是蛮感动的
/************************************************************** Problem: 3996 User: Tunix Language: C++ Result: Accepted Time:584 ms Memory:29152 kb ****************************************************************/ //BZOJ 3996 #include<queue> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define rep(i,n) for(int i=0;i<n;++i) #define F(i,j,n) for(int i=j;i<=n;++i) #define D(i,j,n) for(int i=j;i>=n;--i) #define pb push_back using namespace std; typedef long long LL; inline int getint(){ int r=1,v=0; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; return r*v; } const int N=300010,M=1000010,INF=1e9; /*******************template********************/ int n,ans; struct edge{int to,v;}; struct Net{ edge E[M<<1]; int head ,next[M<<1],cnt; void ins(int x,int y,int z){ E[++cnt]=(edge){y,z}; next[cnt]=head[x]; head[x]=cnt; } void add(int x,int y,int z){ins(x,y,z); ins(y,x,0);} int d ,S,T,cur ; queue<int>Q; bool mklevel(){ memset(d,-1,sizeof d); d[S]=0; Q.push(S); while(!Q.empty()){ int x=Q.front(); Q.pop(); for(int i=head[x];i;i=next[i]) if (d[E[i].to]==-1 && E[i].v){ d[E[i].to]=d[x]+1; Q.push(E[i].to); } } return d[T]!=-1; } int dfs(int x,int a){ if (x==T) return a; int flow=0; for(int &i=cur[x];i && flow<a;i=next[i]) if (d[E[i].to]==d[x]+1 && E[i].v){ int f=dfs(E[i].to,min(E[i].v,a-flow)); E[i].v-=f; E[i^1].v+=f; flow+=f; } if (!flow) d[x]=-1; return flow; } void Dinic(){ while(mklevel()){ F(i,S,T) cur[i]=head[i]; ans-=dfs(S,INF); } } void init(){ cnt=1; ans=0; n=getint(); S=0; T=n*(n+1)+1; int x; F(i,1,n) F(j,1,n){ x=getint(); add(i*n+j,T,x); add(i,i*n+j,INF); add(j,i*n+j,INF); ans+=x; } F(i,1,n){ x=getint(); add(S,i,x); } Dinic(); printf("%d\n",ans); } }G1; int main(){ #ifndef ONLINE_JUDGE freopen("3996.in","r",stdin); freopen("3996.out","w",stdout); #endif G1.init(); return 0; }
View Code
3996: [TJOI2015]线性代数
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 590 Solved: 414
[Submit][Status][Discuss]
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
输出最大的DSample Input
31 2 1
3 1 0
1 2 3
2 3 7
Sample Output
2HINT
1<=N<=500Source
[Submit][Status][Discuss]相关文章推荐
- bzoj3996 [TJOI2015]线性代数
- 【BZOJ】3996: [TJOI2015]线性代数
- bzoj3996 [TJOI2015]线性代数
- BZOJ 3996 [TJOI 2015] 线性代数 解题报告
- ●BZOJ 3996 [TJOI2015]线性代数
- BZOJ3996 [TJOI2015]线性代数 【最小割】
- bzoj3996 [TJOI2015]线性代数
- bzoj 3996: [TJOI2015]线性代数
- bzoj 3996: [TJOI2015]线性代数
- 洛谷P3973 - [TJOI2015]线性代数
- [TJOI2015]线性代数
- BZOJ3996: [TJOI2015]线性代数
- 3996: [TJOI2015]线性代数
- BZOJ3997: [TJOI2015]组合数学
- 【BZOJ3998】弦论(TJOI2015)-后缀自动机
- bzoj 4001: [TJOI2015]概率论(找规律)
- bzoj3998 TJOI2015 弦论
- BZOJ 4001 [TJOI2015]概率论 ——找规律
- bzoj 3998: [TJOI2015]弦论(后缀自动机)
- BZOJ 3998: [TJOI2015]弦论