【考试总结】2022-05-10
简单题
使用能维护这个区间历史被加了多少的线段树即可,在每个 的线段上对 进行加法即可
Code Display
const int N=5e5+10;
int len[N<<2],tag[N<<2],cov[N<<2],b[N],n,m,Q;
signed main(){
freopen("easy.in","r",stdin); freopen("easy.out","w",stdout);
n=read(); m=read(); Q=read();
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
auto push_add=[&](const int p,const int v){
if(~cov[p]) b[cov[p]]+=len[p]*v;
else tag[p]+=v;
};
auto push_down=[&](const int p){
if(tag[p]){
push_add(ls,tag[p]);
push_add(rs,tag[p]);
tag[p]=0;
}
if(~cov[p]){
cov[ls]=cov[p];
cov[rs]=cov[p];
cov[p]=-1;
}
};
function<void(int,int,int)>build=[&](const int p,const int l,const int r){
len[p]=r-l+1; cov[p]=-1;
if(l==r) return cov[p]=read(),void();
int mid=(l+r)>>1;
build(lson); build(rson);
};
build(1,1,n);
while(Q--){
int opt=read(),st=read(),ed=read(),v=read();
function<void(int,int,int)> Plus=[&](int p,int l,int r){
if(st<=l&&r<=ed) return push_add(p,v);
int mid=(l+r)>>1; push_down(p);
if(st<=mid) Plus(lson); if(ed>mid) Plus(rson);
return ;
};
function<void(int,int,int)> Cover=[&](int p,int l,int r){
if(st<=l&&r<=ed) return cov[p]=v,void();
int mid=(l+r)>>1; push_down(p);
if(st<=mid) Cover(lson); if(ed>mid) Cover(rson);
return ;
};
if(opt==1) Cover(1,1,n); else Plus(1,1,n);
}
function<void(int,int,int)>dfs=[&](const int p,const int l,const int r){
if(l==r) return ;
int mid=(l+r)>>1; push_down(p);
dfs(lson); dfs(rson);
return ;
};
dfs(1,1,n);
rep(i,1,m) print(b[i]);
#undef ls
#undef rs
#undef lson
#undef rson
return 0;
}
树上游走
设 表示第一次经过 且 的子孙都没有经过的,父亲也已经消失的情况下得到的期望权值, 表示同样状况下第二次经过 得到的期望权值
设 表示第一次经过 且 的父亲依然存在,不经过 的父亲得到的期望答案,而 表示不返回父亲的概率
的转移是平凡的,枚举走到了哪个儿子使用 转移即可
剩下三种转移考虑走到儿子之后的处境:
-
走到子树里面不再回头,分别使用 来转移即可
-
走到儿子节点立刻返回,此时仍然可以走到任何一个儿子,不过先前走的再走就得用 转移了
-
走到儿子子树的另一节点再返回,区别在于返回之后儿子不存在了,概率上的处理要减掉上一个情况发生的 以及不再返回的概率
而这个情况在只有一个出边的时候的 转移需要用到自己的权值
边界就是
Code Display
const int N=1e5+10;
int inv[N],f[N],g[N],h[N],p[N];
int n,S,a[N];
vector<int> G[N];
signed main(){
freopen("walk.in","r",stdin); freopen("walk.out","w",stdout);
n=read(); S=read();
for(int i=inv[1]=inv[0]=1;i<=n;++i) a[i]=read();
rep(i,2,n){
inv[i]=mod-mul(mod/i,inv[mod%i]);
int u=read(),v=read();
G[u].emplace_back(v);
G[v].emplace_back(u);
}
function<void(int,int)>solve=[&](int x,int fat){
int deg=0,sumf=0;
for(auto t:G[x]) if(t!=fat){
deg++;
solve(t,x);
ckadd(sumf,f[t]);
}
if(!deg){
f[x]=g[x]=a[x];
return ;
}
for(auto t:G[x]) if(t!=fat){
ckadd(f[x],h[t]);
int dt=G[t].size()-1;
int down=del(1,add(p[t],inv[dt+1])),oth=del(sumf,f[t]);
ckadd(f[x],mul(mul(inv[deg],inv[dt+1]),add(g[t],oth)));
if(deg==1){
ckadd(f[x],mul(a[x],down));
}else{
ckadd(f[x],mul(down,mul(inv[deg-1],oth)));
}
ckadd(g[x],f[t]);
ckadd(h[x],h[t]);
ckadd(p[x],p[t]);
ckadd(h[x],mul(mul(inv[dt+1],inv[deg+1]),add(g[t],oth)));
ckadd(p[x],mul(mul(inv[dt+1],inv[deg+1]),deg));
ckadd(h[x],mul(down,mul(inv[deg],oth)));
ckadd(p[x],mul(down,mul(inv[deg],deg-1)));
}
ckmul(f[x],inv[deg]);
ckmul(g[x],inv[deg]);
ckmul(p[x],inv[deg+1]);
ckmul(h[x],inv[deg+1]);
return ;
};
solve(S,0);
print(f[S]);
return 0;
}
树的同构
枚举每个点作为根作为 点集中深度最小的点,再枚举此时有根树上的另外一个点作为点集 中深度最小的点
设 表示 子树和 子树中包含根的联通块同构最多能在联通块中包含几个点
转移考虑计算出来所有 ,那么可以进行一个二分图最大带权匹配即可,使用费用流时复杂度
Code Display
const int N=500,inf=0x3f3f3f3f3f3f3f3f;
struct Network_Flow{
int incf[N],pre[N],dst[N];
bool inq[N];
int S,T,ecnt=1,tot,head[N];
struct edge{int to,nxt,lim,cst;}e[N<<3];
inline bool spfa(){
for(int i=1;i<=tot;++i) incf[i]=0,dst[i]=-inf;
dst[S]=0; incf[S]=inf;
queue<int> q; q.push(S);
while(q.size()){
int fr=q.front(); q.pop(); inq[fr]=0;
for(int i=head[fr];i;i=e[i].nxt) if(e[i].lim){
int t=e[i].to;
if(dst[fr]+e[i].cst>dst[t]){
dst[t]=dst[fr]+e[i].cst;
incf[t]=min(incf[fr],e[i].lim);
pre[t]=i;
if(!inq[t]) inq[t]=1,q.push(t);
}
}
}
return dst[T]!=-inf;
}
inline void adde(int u,int v,int w,int c){
e[++ecnt]={v,head[u],w,c};
head[u]=ecnt;
}
inline void add(int u,int v,int w,int c){return adde(u,v,w,c),adde(v,u,0,-c);}
inline void clear(){
rep(i,1,tot) head[i]=0;
ecnt=1; tot=0;
}
inline int EK(){
int sum=0;
while(spfa()){
int x=T;
while(x^S){
e[pre[x]].lim-=incf[T]; e[pre[x]^1].lim+=incf[T];
x=e[pre[x]^1].to;
}
sum+=dst[T];
}
return sum;
}
}F;
int u[N],v[N],n,fa[N];
vector<int> G[N];
int dp[N][N],id[N];
signed main(){
freopen("isomorphism.in","r",stdin); freopen("isomorphism.out","w",stdout);
while(~scanf("%lld",&u[++n])) ++u[n];
for(int i=n/2+1;i<=n;++i) v[i-n/2]=u[i];
n=n/2+1;
for(int i=1;i<n;++i) G[u[i]].emplace_back(v[i]),G[v[i]].emplace_back(u[i]);
int ban,ans=0;
function<void(int,int)>get_fa=[&](const int x,const int fat){
fa[x]=fat;
for(auto t:G[x]) if(t!=fat) get_fa(t,x);
return ;
};
function<void(int,int)>DP=[&](const int x,const int y){
if(~dp[x][y]) return ;
if(x==ban){
dp[x][y]=0;
return ;
}
for(auto a:G[x]) if(a!=fa[x]&&a!=ban) for(auto b:G[y]) if(b!=fa[y]) DP(a,b);
F.clear();
F.S=++F.tot; F.T=++F.tot;
for(auto a:G[x]) if(a!=fa[x]&&a!=ban) F.add(F.S,id[a]=++F.tot,1,0);
for(auto a:G[y]) if(a!=fa[y]) F.add(id[a]=++F.tot,F.T,1,0);
for(auto a:G[x]) if(a!=fa[x]&&a!=ban){
for(auto b:G[y]) if(b!=fa[y]){
F.add(id[a],id[b],1,dp[a][b]);
}
}
dp[x][y]=F.EK()+1;
return ;
};
rep(i,1,n){
memset(dp,-1,sizeof(dp));
get_fa(i,0);
rep(j,1,n) ban=j,DP(i,j);
rep(j,1,n) ckmax(ans,dp[i][j]);
}
print(ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律