2024.11.25 考试总结

100+0+50+0,rk10。

T1

简单树形 \(dp\) 带国王游戏经典贪心,时间复杂度 \(O(n\log n)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
int n,f[N],ts[N],cs[N];
struct kng{int t,sum,ed;};
vector<int>g[N],w[N];
vector<kng>kg[N];
int cmp(kng x,kng y){
	return (x.t+x.ed)*y.sum<(y.t+y.ed)*x.sum;
}inline void dfs(int x){
	for(int i=0;i<g[x].size();i++){
		dfs(g[x][i]),cs[x]+=cs[g[x][i]];
		f[x]+=f[g[x][i]],ts[x]+=ts[g[x][i]]+w[x][i];
		kg[x].push_back({ts[g[x][i]],cs[g[x][i]],w[x][i]});
	}sort(kg[x].begin(),kg[x].end(),cmp);int s=0;
	for(auto y:kg[x])
		s+=y.ed,f[x]+=s*y.sum,s+=y.t;
}signed main(){
	freopen("walk.in","r",stdin);
	freopen("walk.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=2,fa,c;i<=n;i++)
		cin>>fa>>c,g[fa].push_back(i),w[fa].push_back(c);
	for(int i=1;i<=n;i++) cin>>cs[i];
	dfs(1),cout<<f[1];
	return 0;
}

T2

问题通过 \(dfs\) 序容易转化为区间推平、区间求和和区间回溯。用可持久化 \(treap\) 维护珂朵莉树即可。时间复杂度 \(O(n\log n)\),空间在一片 \(100MB\) 中达到了 \(1.3GB\),大空间选手可喜可贺。线段树做法懒得想了。

#include<bits/stdc++.h>
#define ls(x) pl[x].ls
#define rs(x) pl[x].rs
#define sz(x) pl[x].sz
#define rk(x) pl[x].rk
#define cl(x) pl[x].cl
#define l(x) pl[x].l
#define r(x) pl[x].r
using namespace std;
const int N=7e7+5;
const int M=5e5+5;
struct fhq{
	int ls,rs,l,r,sz,rk,cl;
}pl[N];int n,id,rt[M],ans[M];
int mk(int l,int r,int c){
	return pl[++id]={0,0,l,r,1,rand(),c},id;
}void push_up(int x){
	sz(x)=sz(ls(x))+sz(rs(x))+1;
}void spilt(int x,int v,int &a,int &b){
	if(!x) return a=b=0,void();
	if(sz(ls(x))<v){
		a=++id,pl[a]=pl[x];
		spilt(rs(x),v-sz(ls(x))-1,rs(a),b);
		push_up(a);
	}else{
		b=++id,pl[b]=pl[x];
		spilt(ls(x),v,a,ls(b));
		push_up(b);
	}
}int merge(int x,int y){
	if(!x&&!y) return 0;
	if(!x||!y){
		pl[++id]=pl[x+y];
		return id;
	}if(rk(x)<rk(y)){
		int re=x;
		rs(re)=merge(rs(re),y);
		return push_up(re),re;
	}int re=y;
	ls(re)=merge(x,ls(re));
	return push_up(re),re;
}int find(int x,int v){
	if(l(x)<=v&&v<=r(x)) return sz(ls(x))+1;
	if(v<l(x)) return find(ls(x),v);
	return find(rs(x),v)+sz(ls(x))+1;
}int sum(int x){
	if(!x) return 0;
	return sum(ls(x))+sum(rs(x))+(1-cl(x))*(r(x)-l(x)+1);
}void assign(int x,int l,int r,int v){
	int lx=find(rt[x],l),a,b,c;
	spilt(rt[x],lx-1,a,b),spilt(b,1,b,c);
	int lc=l(b),rc=r(b),co=cl(b);
	if(lc==l) rt[x]=merge(a,merge(b,c));
	else rt[x]=merge(a,merge(merge(mk(lc,l-1,co),mk(l,rc,co)),c));
	int rx=find(rt[x],r);
	spilt(rt[x],rx-1,a,b),spilt(b,1,b,c);
	lc=l(b),rc=r(b),co=cl(b);
	if(rc==r) rt[x]=merge(a,merge(b,c));
	else rt[x]=merge(a,merge(merge(mk(lc,r,co),mk(r+1,rc,co)),c));
	lx=find(rt[x],l),rx=find(rt[x],r);
	spilt(rt[x],rx,b,c),spilt(b,lx-1,a,b);
	rt[x]=merge(merge(a,mk(l,r,v)),c);
	ans[x]+=sum(b);
}int dfn[M],low[M],ij,q,vis[M];
vector<int>g[M],chg[M];
void dfs(int x){
	dfn[x]=++ij;
	for(auto y:g[x]) dfs(y);
	low[x]=ij; 
}void geta(int x,int fa,int zx){
	ans[x]=ans[fa],rt[x]=++id;
	pl[id]=pl[rt[fa]];
	for(auto i:chg[x])
		assign(x,dfn[i],low[i],1);
	if(vis[x]&&!zx) assign(x,dfn[x],low[x],1);
	for(auto y:g[x]) geta(y,x,vis[x]|zx);
}signed main(){
	freopen("reward.in","r",stdin);
	freopen("reward.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	srand(time(0)),cin>>n>>q;
	for(int i=2,fa;i<=n;i++)
		cin>>fa,g[fa].push_back(i);
	for(int i=1;i<=q;i++){
		int x,y;cin>>x>>y;
		if(x==y) continue;
		chg[x].push_back(y);
		chg[y].push_back(x);
		vis[x]=vis[y]=1;
	}dfs(1),rt[0]=mk(1,n,0),geta(1,0,0);
	for(int i=1;i<=n;i++)
		cout<<ans[i]-(ans[i]>0)<<" ";
	return 0;
}

T3

首先转化为区间问题,然后用单调队列求出每杯奶茶的覆盖区域 \([l,r]\),转一维为二维,问题即转化为给横坐标为 \([l,i]\),纵坐标为 \([i,r]\) 的区间加上奶茶的卡路里数,差分即可。

时间复杂度 \(O(nm+m^2)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5005,M=205;
int n,m,a[N][M],d[N],tp,st[N];
int sm[N][N],lg[N],rg[N],ans;
signed main(){
	freopen("calorie.in","r",stdin);
	freopen("calorie.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=2;i<=m;i++)
		cin>>d[i],d[i]+=d[i-1];
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			cin>>a[i][j];
	for(int j=1;j<=n;j++){
		for(int i=1;i<=m;i++){
			while(tp&&a[st[tp]][j]<=a[i][j]) tp--;
			lg[i]=st[tp]+1,st[++tp]=i;
		}tp=0;
		for(int i=m;i;i--){
			while(tp&&a[st[tp]][j]<a[i][j]) tp--;
			rg[i]=(!tp?m:st[tp]-1),st[++tp]=i;
		}tp=0;
		for(int i=1;i<=m;i++){
			sm[lg[i]][i]+=a[i][j],sm[i+1][rg[i]+1]+=a[i][j];
			sm[i+1][i]-=a[i][j],sm[lg[i]][rg[i]+1]-=a[i][j];
		}
	}for(int i=1;i<=m;i++) for(int j=1;j<=m;j++)
		sm[i][j]+=sm[i-1][j]+sm[i][j-1]-sm[i-1][j-1];
	for(int i=1;i<=m;i++)
		for(int j=i;j<=m;j++)
			ans=max(ans,sm[i][j]-d[j]+d[i]);
	cout<<ans;
	return 0;
}

T4

注意力惊人地注意到原问题可以转化为构造序列 \(t_i\),满足当 \(t_j>t_i,j>i,\max\limits_{k=i+1}^{j-1}t_k\le i\) 时,\(s_i\ne s_j\),很明显是可 \(dp\) 的。设 \(f_{l,r,i}\) 表示区间 \([l,r]\) 中最大值为 \(i\) 时的方案数,预处理前缀和可以达到 \(O(nm^3)\)。继续注意力惊人的注意到 \(f_{l,r}\) 是关于 \(i\)\(r-l\) 次函数,\(sm_{l,r}\) 是关于 \(i\)\(r-l+1\) 次函数,所以直接求出 \(sm_{1,m,k}(0\le k\le m+1)\) 后,拉格朗日插值插出 \(n\) 时的答案即可。

时间复杂度 \(O(m^4)\),注意卡常。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=205,p=1e9+7;
int n,m,s[N],tot,f[N][N][N];
int qpow(int x,int y){
	int re=1;
	while(y){
		if(y&1) re=re*x%p;
		x=x*x%p,y>>=1;
	}return re;
}int lag(int x){
	int re=0;
	for(int i=0,ml=1;i<=m;i++,ml=1){
		for(int j=0;j<=m;j++) if(i!=j)
			ml=ml*(x-j)%p*qpow((i-j+p)%p,p-2)%p;
		re=(re+f[1][m][i]*ml)%p;
	}return re;
}signed main(){
	freopen("message.in","r",stdin);
	freopen("message.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=m;i++) cin>>s[i];
	for(int i=1;i<=m;i++){
		if(s[i]==s[i+1]) continue;
		for(int j=1;j<=m;j++) f[i][i][j]=j;
	}for(int ln=2;ln<=m;ln++)
		for(int l=1,r=ln;r<=m;l++,r++){
			for(int i=1;i<=m;i++){
				if(s[l]!=s[r+1])
					f[l][r][i]=(f[l][r][i]+f[l+1][r][i])%p;
				if(s[r]!=s[r+1])
					f[l][r][i]=(f[l][r][i]+f[l][r-1][i-1])%p;
			}for(int k=l+1;k<r;k++) if(s[k]!=s[r+1]) for(int i=1;i<=m;i++)
				f[l][r][i]=(f[l][r][i]+f[l][k-1][i-1]*f[k+1][r][i])%p;
			for(int i=1;i<=m;i++)
				f[l][r][i]=(f[l][r][i]+f[l][r][i-1])%p;
		}
	cout<<lag(n);
	return 0;
}
posted @ 2024-11-25 17:30  长安一片月_22  阅读(11)  评论(0编辑  收藏  举报