咕了好久的(day8)
首先我们可以选出(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;
}
这个数据范围一眼网络流二分图
我们发现一句很奇怪的话:我们可以让这(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;
}
这题一看对子树就可以想(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;
}