【Plan 第四场】


题目:见2013-5 day2

QAQ大滚粗。。。



A

对于30%的数据,是bzoj1016的加强版,我太弱了只会这个。。。满分算法待研究。。。

50分状压DP,不嫌麻烦可以写一写,,,100%的算法不敢看“基于欧几里得的迭代消元”神马东西。。。。。。。。。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define rep(i,l,r) for(int i=(l),_=(r);i<=_;i++)
#define per(i,r,l) for(int i=(r),_=(l);i>=_;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define INE(i,u) for(int i=head[u];~i;i=e[i].next)
#define LL long long
inline const int read()
{int r=0,k=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}
////////////////////////////////////////////////
const int N=110;
const int M=10010;
int n,m,p,k;
struct edge{int u,v,w;}e[M];
int fa[N];
struct data{int l,r,cnt;}a[M];
int cnt=0;
LL ans=1;
int curw;
////////////////////////////////////////////////
bool cmp(edge x,edge y){return x.w<y.w;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int find2(int x){return x==fa[x]?x:find2(fa[x]);}
bool unio(int u,int v)
{
	int fu=find(u),fv=find(v);
	if(fu==fv) return 0;
	return fa[fu]=fv,1;
}
int dfs(int cur,int cnt)
{
	int res=0;
	if(cur == a[curw].r+1)
	{
		if(cnt==a[curw].cnt) res++;
		return res;
	}
	res+=dfs(cur+1,cnt);
    int fu=find2(e[cur].u),fv=find2(e[cur].v);
    if(fu!=fv)
    {
    	fa[fu]=fv; cnt++;
    	res+=dfs(cur+1,cnt);
    	fa[fu]=fu;
    }
	return res;
}
////////////////////////////////////////////////
void input()
{
    n=read(); m=read(); p=read();
    rep(i,1,m) e[i]=(edge){read(),read(),read()};
    sort(&e[1],&e[m+1],cmp);
}
void solve()
{
	rep(i,1,n) fa[i]=i;
	int blk=n;
	cnt=1;
	rep(i,1,m)
	{
		if(e[i].w!=e[i-1].w)
		{
			a[cnt].r=i-1;
			cnt++;
			a[cnt].l=i;
		}
		if(unio(e[i].u,e[i].v)) blk--,a[cnt].cnt++;
		if(blk==1) break;
	}
	for(a[cnt].r=a[cnt].l;e[a[cnt].l].w == e[a[cnt].r+1].w;a[cnt].r++);
	rep(i,1,n) fa[i]=i;
	blk=n;
	rep(i,1,cnt)
	{
		curw=i;
		ans=ans*dfs(a[i].l,0)%p;
		rep(j,1,n) fa[j]=j;
		rep(j,1,a[i].r) unio(e[j].u,e[j].v);
	}
	cout<<ans<<endl;
}
////////////////////////////////////////////////
int main()
{
    freopen("mst.in","r",stdin); freopen("mst.out","w",stdout);
    input(),solve();
    return 0;
}


B

这题秒了,第一感觉就是贪心,也比较好证

考虑如果有一条最大的链没选的话,那么他公共部分与他最长的那条链,交换肯定更优

题解上说,用费用流是不退流的,所以可以贪心,我还是没看到本质啊。。。。。。

然后用dfs序+线段树维护就可以了

有个地方写麻烦了,我用并查集实现压缩路径,事实上每次取的都是到根的,遇到0就可以终止

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <stack>
using namespace std;
#define rep(i,l,r) for(int i=(l),_=(r);i<=_;i++)
#define per(i,r,l) for(int i=(r),_=(l);i>=_;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define INE(i,u) for(int i=head[u];~i;i=e[i].next)
#define LL long long
typedef pair<LL,int> pli;
inline const int read()
{int r=0,k=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}
////////////////////////////////////////////////
const int N=200010;
int n,k;
struct edge{int v,next;}e[2*N];
int head[N],kk;
int w[N],fa[N];
int in[N],out[N],ind,_in[N];
pli mx[N*4];
LL dis[N];
LL lz[N*4];
////////////////////////////////////////////////
namespace UFS
{////////////////////////////
int f[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
}////////////////////////////
void adde(int u,int v){e[kk]=(edge){v,head[u]};head[u]=kk++;}
void dfs()
{
	static stack<int>s;
	s.push(1);
	while(!s.empty())
	{
		int u=s.top(),f=0;
		if(!in[u]) in[u]=++ind;
		INE(i,u)
		{
			int v=e[i].v; if(v==fa[u] || in[v]) continue;
			dis[v]=dis[u]+w[v];
			fa[v]=u;
			s.push(v);
			f=1;
		}
		if(!f)
		{
			out[u]=ind;
			INE(i,u)
			{
				int v=e[i].v; if(v==fa[u]) continue;
			}
			s.pop();
		}
	}
	rep(i,1,n) _in[in[i]]=i;
}
#define LS o<<1,L,mid
#define RS o<<1|1,mid+1,R
void pushdown(int o)
{
	if(lz[o])
	{
		mx[o<<1].first+=lz[o];
		mx[o<<1|1].first+=lz[o];
		lz[o<<1]+=lz[o];
		lz[o<<1|1]+=lz[o];
		lz[o]=0;
	}
}
void build(int o,int L,int R)
{
	if(L==R)
	{
		mx[o].first=dis[_in[L]];
		mx[o].second=L;
		return;
	}
	int mid=L+R>>1;
	build(LS); build(RS);
	mx[o]=max(mx[o<<1],mx[o<<1|1]);
}
void add(int l,int r,LL x,int o,int L,int R)
{
	if(l<=L && R<=r)
	{
		mx[o].first+=x;
		lz[o]+=x;
		return;
	}
	pushdown(o);
	int mid=L+R>>1;
	if(r<=mid) add(l,r,x,LS);
	else if(l>mid) add(l,r,x,RS);
	else add(l,mid,x,LS), add(mid+1,r,x,RS);
	mx[o]=max(mx[o<<1],mx[o<<1|1]);
}
pli getmax(int l,int r,int o,int L,int R)
{
	if(l<=L && R<=r) return mx[o];
	pushdown(o);
	int mid=L+R>>1;
	if(r<=mid) return getmax(l,r,LS);
	else if(l>mid) return getmax(l,r,RS);
	else return max(getmax(l,mid,LS),getmax(mid+1,r,RS));
}
////////////////////////////////////////////////
void input()
{
	MS(head,-1);
    n=read(); k=read();
    rep(i,1,n) w[i]=read();
    rep(i,2,n)
    {
    	int u=read(),v=read();
    	adde(u,v); adde(v,u);
    }
}
void solve()
{
	dis[1]=w[1]; dfs();
	build(1,1,n);
	rep(i,1,n) UFS::f[i]=i;
	LL ans=0;
	rep(i,1,k)
	{
		pli ret=getmax(1,n,1,1,n);
		ans+=ret.first;
		int u=_in[ret.second];
		using namespace UFS;
		for(;u;u=f[u])
		{
			add(in[u],out[u],-w[u],1,1,n);
			f[u]=find(fa[u]);
		}
	}
	cout<<ans<<endl;
}
////////////////////////////////////////////////
int main()
{
    freopen("galgame.in","r",stdin); freopen("galgame.out","w",stdout);
    input(),solve();
    return 0;
}


C

这题我遇到过4次了,是一道神题,没敢碰。。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值