题目大意:一个01序列,花费
cij
可以知道sum(i,j)的奇偶性
求最少花费多少钱可以还原这个序列
题解:把前缀和数组当作点
知道sum(i,j)的奇偶性=知道sum[j]-sum[i-1]的奇偶性
还原序列=知道所有sum[]的奇偶性
发现这个东西是可以互推的,所以把所有点联通就可以了
在(i−1,j)连权为cij的边
我的收获:神奇建模……区间和转前缀和端点
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=2005;
#define rep(i,x,y) for(int i=x;i<=y;i++)
int n,t,z,cnt;
int f[M];
long long ans;
struct edge{int u,v,val;}e[M*M];
bool operator <(edge a,edge b){return a.val<b.val;}
void add(int x,int y,int z){e[++t].u=x,e[t].v=y,e[t].val=z;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void uniom(int x,int y,int z)
{
x=find(x),y=find(y);
if(x!=y) f[x]=y,ans+=z,cnt++;
}
void kruskal()
{
sort(e+1,e+1+t);
rep(i,1,n) f[i]=i;
rep(i,1,t){
uniom(e[i].u,e[i].v,e[i].val);
if(cnt==n) break;
}
}
void work()
{
kruskal();
cout<<ans<<endl;
}
void init()
{
cin>>n;
rep(i,1,n) rep(j,i,n) cin>>z,add(i-1,j,z);
}
int main()
{
init();
work();
return 0;
}