• 雅礼集训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;
    }
    
  • 相关阅读:
    wxpython仿写记事本
    HIVE提交command过程图
    SQL编辑器自动提醒实现
    hive.sh的内容分析
    Hive配置项的含义详解(5)
    比特币、莱特币来一发?
    引导孩子从“打针有点疼”开始
    For Wife
    我是真的爱你
    .net core 添加本地dll
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12791393.html
Copyright © 2020-2023  润新知