雅礼集训2017day8乱写

咕了好久的(day8)

t1

首先我们可以选出(k)个点作为奇数深度的点,方案数是(C_{k-1}^{n-1})

考虑一下这颗树,一定是一张二分图,偶数点作为左侧节点,奇数点作为右侧节点

问题变为 一个(n+m)个节点的二分图的生成树方案数

考虑模拟(prufer)序列构造树的过程,最后两个点接要连边,所以要在二分图的左侧和右侧各留下一个节点

所以(prufer)序列构造的方案数是(n^{m-1}*m^{n-1})

最后的答案就是((n-k)^{k-1}*k^{n-k-1}*C_{k-1}^{n-1})

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=1e5+10;
	int n,m,p,ret; 
	inline int fast(int x,int k)
	{
		if(k<0) return 0;
		int ret=1;
		while(k)
		{
			if(k&1) ret=ret*x%p;
			x=x*x%p;
			k>>=1;
		}
		return ret;
	}
	int C(int n,int m)
	{
		if(n<m) return 0;
		int sum1=1,sum2=1;
		for(int i=m+1;i<=n;++i) sum1=sum1*i%p;
		for(int i=1;i<=n-m;++i) sum2=sum2*i%p;
		return sum1*fast(sum2,p-2)%p;
	}
	int c[1010][1010];
	inline void solve1()
	{
		for(int i=0;i<=n;++i)
		{
			c[i][0]=1;
			for(int j=1;j<=i;++j)
			{
				c[i][j]=(c[i-1][j-1]+c[i-1][j])%p;
			}
		}
		printf("%lld
",c[n-1][m-1]*fast(m,n-m-1)%p*fast(n-m,m-1)%p);
	}
	inline void solve2()
	{
		printf("%lld
",C(n-1,m-1)*fast(m,n-m-1)%p*fast(n-m,m-1)%p);
	}
	inline void main()
	{
		n=read(),m=read(),p=read();
		if(n<=1000) solve1();
		else solve2();
	}
}
signed main()
{
	red::main();
	return 0;
}

t2

这个数据范围一眼网络流二分图

我们发现一句很奇怪的话:我们可以让这(n)种减肥药每一种对应一个其使用的药材

翻译一下就是如果把含有药材(i)的药全部选上,一定选择的药种类等于使用的药材种类数

这就好办了,考虑最大闭合权子图

(2*n)个点表示(n)种药和药材

我们从(S)向每种药点连上(inf-p_i)流量的边,每种药材向每个(T)点连(inf)

然后每种药向需要的药材连(inf)

用最小割减去(sumlimits_{i=1}^{n}inf-p_i)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=1e5+10,inf=0x3f3f3f3f;
	int n,st,ed,ret,sum;
	int head[N],cnt=1;
	struct point
	{
		int nxt,to,val;
		point(){}
		point(const int &nxt,const int &to,const int &val):nxt(nxt),to(to),val(val){}
	}a[N<<1];
	inline void link(int x,int y,int z)
	{
		a[++cnt]=(point){head[x],y,z};head[x]=cnt;
		a[++cnt]=(point){head[y],x,0};head[y]=cnt;
	}
	int dis[N],cur[N];
	queue<int> q;
	inline bool bfs()
	{
		for(int i=1;i<=ed;++i) dis[i]=0,cur[i]=head[i];
		q.push(st);dis[st]=1;
		while(!q.empty())
		{
			int now=q.front();
			q.pop();
			for(int i=head[now];i;i=a[i].nxt)
			{
				int t=a[i].to;
				if(!dis[t]&&a[i].val)
				{
					dis[t]=dis[now]+1;
					q.push(t);
				}
			}
		}
		return dis[ed];
	}
	inline int dfs(int now,int c)
	{
		if(now==ed||!c) return c;
		int ret=c,f;
		for(int i=cur[now];i;i=a[i].nxt)
		{
			cur[now]=i;
			int t=a[i].to;
			if(dis[t]==dis[now]+1)
			{
				f=dfs(t,min(a[i].val,ret));
				ret-=f;
				a[i].val-=f;
				a[i^1].val+=f;
				if(!ret) return c;
			}
		}
		if(ret==c) dis[now]=0;
		return c-ret;
	}
	inline void dinic()
	{
		while(bfs()) ret+=dfs(st,inf); 
	}
	inline void main()
	{
		n=read();st=2*n+1,ed=2*n+2;
		for(int s,x,i=1;i<=n;++i)
		{
			s=read();
			for(int j=1;j<=s;++j)
			{
				x=read();
				link(i,x+n,inf);
			}
		}
		for(int x,i=1;i<=n;++i)
		{
			x=read();
			link(st,i,inf-x);
			link(i+n,ed,inf);
			sum+=inf-x;
		}
		dinic();
		ret=ret-sum;
		printf("%lld
",ret);
	}
}
signed main()
{
	red::main();
	return 0;
}

t3

这题一看对子树就可以想(dfs)序了

(dfs)序分类之后发现好像是区间加和区间(k)大值

这个东西应该是分块入门(2)

考虑分块,外层可以二分答案,块内排序,二分查找(mid)的排名

一根号两(log),拿头过

然后发现(lenge 10),考虑块内直接维护值域前缀和,实现(O(1))查询

如果说块内值域相差过大,或块内元素过多,新开一块

还需要定期重构

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=2e5+10,inf=0x3f3f3f3f;
	int n,m,len,s=2000,sz=300;
	int head[N],cnt=1;
	struct point
	{
		int nxt,to,val;
		point(){}
		point(const int &nxt,const int &to,const int &val):nxt(nxt),to(to),val(val){}
	}e[N<<1];
	inline void link(int x,int y,int z)
	{
		e[++cnt]=(point){head[x],y,z};head[x]=cnt;
	}
	int st[N],ed[N],idx;
	int a[N],b[N];
	inline void dfs(int now,int dep)
	{
		st[now]=++idx;
		a[idx]=dep;
		for(int i=head[now];i;i=e[i].nxt)
		{
			int t=e[i].to;
			dfs(t,dep+e[i].val);
		}
		ed[now]=idx;
	}
	int tl[N],tr[N];
	int d[N],sum[1010][20010],pl[N],pr[N],tot;
	inline void pushdown(int x)
	{
		if(!d[x]) return;
		for(int i=tl[x];i<=tr[x];++i) a[i]+=d[x];
		d[x]=0;
	}
	inline void update(int x)
	{
		pl[x]=inf,pr[x]=-inf;
		for(int i=tl[x];i<=tr[x];++i)
		{
			pl[x]=min(pl[x],a[i]);
			pr[x]=max(pr[x],a[i]);
		}
		for(int i=0;i<=pr[x]-pl[x];++i) sum[x][i]=0;
		for(int i=tl[x];i<=tr[x];++i) ++sum[x][a[i]-pl[x]];
		for(int i=1;i<=pr[x]-pl[x];++i) sum[x][i]+=sum[x][i-1];
	}
	inline void build()
	{
		for(int i=1;i<=tot;++i) pushdown(i);
		int now=1,l=inf,r=-inf;tl[1]=1;
		for(int i=1;i<=n;++i)
		{
			l=min(l,a[i]);
			r=max(r,a[i]);
			if(r-l>s||i-tl[now]>=sz)
			{
				tr[now]=i-1;
				tl[++now]=i;
				l=r=a[i];
			}
			tr[b[i]=now]=i;
		}
		tot=now;
		for(int i=1;i<=tot;++i) update(i);
	}
	inline int getsum(int p,int x)
	{
		if(x<pl[p]) return 0;
		if(x>pr[p]) return sum[p][pr[p]-pl[p]];
		return sum[p][x-pl[p]];
	}
	inline int query(int l,int r,int x)
	{
		int ret=0,bl=b[l],br=b[r];
		if(bl==br)
		{
			for(int i=l;i<=r;++i)
				if(a[i]<=x) ++ret;
			return ret;
		}
		for(int i=l;i<=tr[bl];++i)
			if(a[i]<=x) ++ret;
		for(int i=tl[br];i<=r;++i)
			if(a[i]<=x) ++ret;
		for(int i=bl+1;i<br;++i) ret+=getsum(i,x);
		return ret;
	}
	inline int getth(int l,int r,int k)
	{
		int bl=b[l],br=b[r];
		pushdown(bl),pushdown(br);
		if(r-l+1<k) return -1;
		int t1=inf,t2=-inf;
		for(int i=bl;i<=br;++i)
			t1=min(t1,pl[i]),t2=max(t2,pr[i]);
		if(t1==t2) return t1;
		int ans=t1;
		while(t1<=t2)
		{
			int mid=(t1+t2)>>1;
			if(query(l,r,mid)>=k) ans=mid,t2=mid-1;
			else t1=mid+1;
		}
		return ans;
	}
	inline void change(int l,int r,int x)
	{
		int bl=b[l],br=b[r];
		if(bl==br)
		{
			pushdown(bl);
			for(int i=l;i<=r;++i)
				a[i]+=x;
			update(bl);
			return;
		}
		pushdown(bl);
		for(int i=l;i<=tr[bl];++i)
			a[i]+=x;
		update(bl);
		pushdown(br);
		for(int i=tl[br];i<=r;++i)
			a[i]+=x;
		update(br);
		for(int i=bl+1;i<br;++i) d[i]+=x,pl[i]+=x,pr[i]+=x;
	}
	inline void main()
	{
		n=read(),m=read(),len=read();
		for(int x,y,i=2;i<=n;++i)
		{
			x=read(),y=read();
			link(x,i,y);
		}
		dfs(1,0);
		build();
		for(int opt,x,y,i=1;i<=m;++i)
		{
			opt=read(),x=read(),y=read();
			if(opt==1) printf("%d
",getth(st[x],ed[x],y));
			else change(st[x],ed[x],y);
			if(i%1000==0) build();
		}
	}
}
signed main()
{
	red::main();
	return 0;
}
原文地址:https://www.cnblogs.com/knife-rose/p/12791393.html