bzoj 权限。。
啊!考试第二题啊。
60分。。主要原因 数组开小了 开了个正解的根号。。。
说说题吧:
魔术师的桌子上有n个杯子排成一行,编号为1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。花费cijcij元,魔术师就会告诉你杯子i,i+1,…,j底下藏有球的总数的奇偶性。
采取最优的询问策略,你至少需要花费多少元,才能保证猜出哪些杯子底下藏着球?
分析:
知道了 c i j 就可以知道 i- j 的奇偶性。。即 sum【j】-sum【i-1】就知道了。 然后我现在需要知道sum【i】-sum【i-1】的也就是 第i个杯子有没有球。 然后sum【0】的奇偶性是知道的。也就是0。那么我现在要知道所有杯子底下的藏球情况,需要的最小费用。就是有一个01序列,,我们要确定每一个的状态所需要的钱。我现在把他们划分成了一些区间。我只有在吧每个区间都划分为长度为1时才可以确定每一个。那就应该是n-1条连线。
哎》 哪里不太对! n个点 n-1条连线 最小费用 这不是 最小生成树吗!
而现在我的c【i】【j】其实表示的是从sum[j]-sum[i-1],也就是我要知道n条边得树。所以我要建从0到n的树!
我们用人话说一遍:
建一个0到n的树,求最小生成树。
额鹅鹅鹅 朕 用prim写了个 稍显冗长且麻烦的代码 的了60分 因为RE!!
然后的 小胖的奇偶 恩
所以 改了改
:
ps 堆优化并么什么卵用。。。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 999999999
using namespace std;
//by mars_ch
//并查集 最小生成树???? dp qujian 堆优化
//aaaa
struct edge
{
int x,y,v,ne;
bool operator <(const edge &a) const
{
return a.v<v;
} // interesting
}e[5000005]; //2005*2005啊啊啊!!
priority_queue<edge> q;
int tot,v[2005],h[2005],d[2005],n;
void add(int x,int y,int v)
{
e[++tot].y=y;
e[tot].v=v;
e[tot].ne=h[x];
h[x]=tot;
}
void prim()
{
long long ans=0;
for(int i=1;i<=n;i++)
{
d[i]=inf,v[i]=0;
}
edge x;
x.x=0,x.v=0;
d[0]=0;
q.push(x);
while (!q.empty())
{
x=q.top();
q.pop();
if (v[x.x] == 1) continue;
v[x.x]=1;
ans+=x.v;
for (int i=h[x.x];i!=-1;i=e[i].ne)
{
int yy=e[i].y;
if (v[yy] == 0 && e[i].v<d[yy])
{
edge temp;
d[yy]=e[i].v;
temp.x=yy;
temp.v=e[i].v;
q.push(temp);
}
}
}
printf("%lld\n",ans);
}
int main()
{
scanf("%d",&n);
memset(h,-1,sizeof(h));
for (int i=1;i<=n;i++)
for (int j=i;j<=n;j++)
{
int x;
scanf("%d",&x);
// add(i,j,x);
add(i-1,j,x);
add(j,i-1,x);
}
prim();
return 0;
}