最近做题遇到的坑·三 cf429c,cf377d,cf288d,cf294e,cf958b2,cf765e,cf812e,gym101981d,gym101981g

博客分享了多道算法题的解题情况,包括cf429c、cf377d等题目。涉及树结构、节点选择、链的相交与合并、树上博弈等问题,还提到了最小球覆盖、数数题等,给出了部分题目的解题思路和方法。

cf429c

给一个序列 a 1 . . a n a_1..a_n a1..an,能否找到一棵n个节点的,且每个非叶子节点有至少2个叶子的树,使每个节点子树大小一一对应于序列a中的一个数
n<=24

暴力都不会写。。直接搞搞就好了

#include<bits/stdc++.h>
using namespace std;
int n,a[25],tot;
int st[12],top;
void dfs(int d) {
	if(d>tot) cout<<"YES",exit(0);
	for(int i=1;i<=top;++i) {
		if(st[i]>=a[d]&&(st[i]>a[d]||st[i]!=a[i]-1)) {
			st[i]-=a[d];
			st[++top]=a[d]-1;
			dfs(d+1);
			st[i]+=a[d];
			--top;
		}
	}
}
int main() {
	cin>>n;
	for(int i=1;i<=n;++i) {
		cin>>a[i];
		if(a[i]==2) return cout<<"NO",0;
		if(a[i]>1) ++tot;
	}
	sort(a+1,a+n+1,greater<int>());
	if(a[1]!=n) return cout<<"NO",0;
	st[top=1]=a[1]-1;
	dfs(2);
	cout<<"NO";
}

cf377d

n个人,每个人有值 l i ≤ v i ≤ r i l_i\le v_i\le r_i liviri,要选一些人是人数最多,满足选中的人中 m a x { v i } ≤ m i n { r i } , m i n { v i } ≥ m a x { l i } max\{v_i\}\le min\{r_i\},\quad min\{v_i\}\ge max\{l_i\} max{vi}min{ri},min{vi}max{li}
n<=1e5

想不到,,看题解:搞一个公共边界L,R,
则要满足l_i<=L<=v_i, v_i<=R<=r_i,
可以看成二维的一个矩形区域,求n个矩形最多的重叠次数(怎么想到的呢

cf288d

求一棵树中有多少对不相交的链

菜如我,往往会把简单的题意讨论的极为复杂。。
我试图分类讨论两条链交的是人型的链、丿型的链、点,点又分四叉、三叉、两叉,然后@#¥%……&#。。。
只要看对每个点u,以它为最高点的所有链,要么与 同样以u为最高点的链 相交,要么与最高点在u的子树外,且另一端点在u的子树内的链 相交
这样就把所有情况不重不漏算了一次

//贺!
#include<bits/stdc++.h>
using namespace std;
const int maxn = 8e4+6;
int n;
long long s[maxn];
long long ans = 0;
vector<int> E[maxn];
void dfs(int x,int f){
    s[x]=1;
    long long tmp = 0;
    for(int i=0;i<E[x].size();i++){
        int v=E[x][i];
        if(v==f)continue;
        dfs(v,x);
        tmp+=1ll*s[x]*s[v];
        s[x]+=s[v];
    }
    ans-=1ll*tmp*(tmp+2LL*s[x]*(n-s[x]));
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        E[a].push_back(b);
        E[b].push_back(a);
    }
    ans=1ll*n*(n-1LL)/2LL*(n*(n-1LL)/2LL);
    dfs(1,0);
    cout<<ans<<endl;
}

cf294e

一棵边带权树,进行一次操作,删一条边,再把这条边加到任意两个点之间,使树仍是树。
求操作后所有链的权值和的最小值
n<=5000

果然不出所料,xjb dfs就行了,就是写的太慢了

#pragma GCC optimize("inline",2)
#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
#define RESET(a) memset(a,0,sizeof a)
#define int long long
using namespace std;
typedef long long LL;
const int N=5005;
const LL inf=1e18;
int n,hd[N],nxt[N<<1],to[N<<1],w[N<<1],tot=1;
int sz[N<<1];
LL aa[N<<1],eg[N<<1];
void add(int a,int b,int c) {
	nxt[++tot]=hd[a],to[tot]=b,w[tot]=c;
	hd[a]=tot;
}
LL dfs1(int u,int fe,LL d) {
	LL re=d;
	for(int i=hd[u];i;i=nxt[i])
		if(i!=fe) re+=dfs1(to[i],i^1,d+w[i]);
	return eg[fe]=re;
}
int dfs2(int u,int fe) {
	int re=1;
	for(int i=hd[u];i;i=nxt[i])
		if(i!=fe) re+=dfs2(to[i],i^1);
	sz[fe^1]=n-re;
	return sz[fe]=re;
}
void solve(int rt) {
	RESET(eg);
	LL sum=dfs1(rt,0,0);
	FOR(i,2,tot) aa[i]=min(aa[i],sum-eg[i]);
}
int zz[N];
LL wi[N],wo[N],bb[N<<1];
void dfs3(int u,int fe) {
	zz[u]=1;
	wi[u]=0,wo[u]=0;
	for(int i=hd[u];i;i=nxt[i]) if(i!=fe) {
		dfs3(to[i],i^1);
		zz[u]+=zz[to[i]];
		wi[u]+=wi[to[i]];
		wo[u]+=wo[to[i]]+zz[to[i]]*w[i];
		wi[u]-=(wo[to[i]]+zz[to[i]]*w[i])*zz[to[i]];
	}
	wi[u]+=wo[u]*zz[u];
	bb[fe]=wi[u];
}
signed main() {
	memset(aa,0x3f,sizeof aa);
	cin>>n;
	FOR(i,1,n-1) {
		int x,y,z;
		cin>>x>>y>>z;
		add(x,y,z);
		add(y,x,z);
	}
	FOR(i,1,n) dfs3(i,0);
	FOR(i,1,n) solve(i);
	dfs2(1,0);
	LL ans=1e18;
	FOR(i,1,n-1) {
		int r=i<<1,s=i<<1|1;
		ans=min(ans,1LL*w[r]*sz[r]*sz[s]+aa[r]*sz[r]+aa[s]*sz[s]
			+bb[r]+bb[s]);
	}
	cout<<ans<<endl;
}

cf958b2

一棵树,求在树上标记1,2,…,n个点分别最多能占领多少个节点
若一个节点在两个被标记节点的路径上,则它被占领

果然先找个直径的端点就行 然后一直选 能使当前的覆盖增加最多的叶子就行了
我还写了个线段树,太蠢了

#pragma GCC optimize("inline",2)
#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
#define reset(a) memset(a,0,sizeof a)
using namespace std;
const int N=1e5+5;
int n,fa[N],st[N],ed[N],pos[N],dep[N],vi[N],Q[N],rt,cnt;
int mx[N<<2],mk[N<<2];
vector<int> e[N];
void getrt() {
	int L=0,R=1; Q[1]=1;
	while(L<R) {
		int u=Q[++L];
		for(auto v:e[u]) if(!vi[v]) {
			vi[v]=1;
			Q[++R]=v;
		}
	}
	reset(vi);
	rt=Q[R];
}
void dfs(int u,int f,int d) {
	fa[u]=f,dep[u]=d,pos[st[u]=++cnt]=u;
	for(auto v:e[u]) if(v!=f) {
		dfs(v,u,d+1);
	}
	ed[u]=cnt;
}
void pushup(int u) {
	mx[u]=max(mx[u<<1],mx[u<<1|1]);
}
void pushdn(int u) {
	mk[u<<1]+=mk[u];
	mk[u<<1|1]+=mk[u];
	mx[u<<1]+=mk[u];
	mx[u<<1|1]+=mk[u];
	mk[u]=0;
}
void build(int u,int l,int r) {
	if(l==r) mx[u]=dep[pos[l]]-1;
	else {
		int mi=l+r>>1;
		build(u<<1,l,mi);
		build(u<<1|1,mi+1,r);
		pushup(u);
	}
}
void upd(int u,int l,int r,int L,int R,int w) {
	if(L<=l&&r<=R) mx[u]+=w,mk[u]+=w;
	else {
		pushdn(u);
		int mi=l+r>>1;
		if(L<=mi) upd(u<<1,l,mi,L,R,w);
		if(R>mi) upd(u<<1|1,mi+1,r,L,R,w);
		pushup(u);
	}
}
pair<int,int> qry(int u,int l,int r) {
	if(l==r) return make_pair(mx[u],l);
	pushdn(u);
	int mi=l+r>>1;
	if(mx[u<<1]>mx[u<<1|1]) return qry(u<<1,l,mi);
	return qry(u<<1|1,mi+1,r);
}
void modi(int u) {
	if(vi[u]) return;
	vi[u]=1;
	upd(1,1,n,st[u],ed[u],-1);
	modi(fa[u]);
}
int main() {
	cin>>n;
	FOR(i,1,n-1) {
		int x,y;
		cin>>x>>y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	getrt();
	dfs(rt,0,1);
	build(1,1,n);
	vi[rt]=1;
	int ans=1;
	cout<<ans;
	FOR(i,2,n) {
		auto pr=qry(1,1,n);
		ans+=pr.first;
		cout<<' '<<ans;
		modi(pos[pr.second]);
	}
}
#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
#define RESET(a) memset(a,0,sizeof a)
using namespace std;
typedef long long LL;
const int N=1e5+5;
vector<int> e[N],b;
int n,dep[N],mxd[N],rt;

void dfs(int u,int f,int d) {
	mxd[u]=dep[u]=d;
	for(auto v:e[u]) if(v!=f) {
		dfs(v,u,d+1);
		mxd[u]=max(mxd[u],mxd[v]);
	}
}

void dfs2(int u,int f,int d) {
	if((f||n==1)&&e[u].size()==1) b.push_back(d);
	int s=-1;
	for(auto v:e[u]) if(v!=f) {
		if(s==-1||mxd[s]<mxd[v]) s=v;
	}
	if(~s) dfs2(s,u,d+1);
	for(auto v:e[u]) if(v!=f&&v!=s) dfs2(v,u,1);
}
int main() {
	cin>>n;
	FOR(i,1,n-1) {
		int x,y;
		cin>>x>>y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(1,0,1);
	FOR(i,1,n) if(dep[rt]<dep[i]) rt=i;
	dfs(rt,0,1);
	dfs2(rt,0,1);
	sort(b.begin(),b.end(),greater<int>());
	int ans=0;
	cout<<1;
	FOR(i,0,n-2) {
		if(i<b.size()) ans+=b[i];
		cout<<' '<<ans;
	}
}

cf765e
在这里插入图片描述

一棵树,如图的链可以合并,问能不能合并,合并的最短长度

果然是直接找直径的中点,然后以它为根看看能不能合并就好了
合并成一条链后如果长度是偶数还要继续对折。。

#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
using namespace std;
typedef long long LL;
const int N=2e5+5;
int n,dep[N],fa[N];
vector<int> e[N];

void dfs(int u,int f,int d) {
	fa[u]=f; dep[u]=d;
	for(auto v:e[u]) if(v!=f) dfs(v,u,d+1);
}
int solve(int u,int f) {
	int re=0,re2=0;
	for(auto v:e[u]) if(v!=f) {
		int t=solve(v,u);
		if(t==-1) return -1;
		if(!re) re=t;
		else if(re!=t) {
			if(!f&&(!re2||re2==t)) re2=t;
			else return -1;
		}
	}
	if(!f) return re+re2;
	return re+1;
}
int main() {
	int ans=1e9,t;
	cin>>n;
	FOR(i,1,n-1) {
		int x,y;
		cin>>x>>y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(1,0,1);
	int u1=1;
	FOR(i,2,n) if(dep[u1]<dep[i]) u1=i;
	
	dfs(u1,0,1);
	int u2=1;
	FOR(i,2,n) if(dep[u2]<dep[i]) u2=i;
	
	int p=u2;
	while(dep[p]>(dep[u1]+dep[u2]+1)/2) p=fa[p];
	
	if((t=solve(p,0))!=-1) ans=min(ans,t);
	
	if(fa[p]) {
		p=fa[p];
		if((t=solve(p,0))!=-1) ans=min(ans,t);
	}
	if(ans==1e9) return cout<<-1,0;
	
	while(ans&1^1) ans>>=1;

	cout<< (ans<1e9 ? ans : -1) << endl;
}

cf812e

树上博弈,如何如何。。

https://blog.csdn.net/weixin_34151004/article/details/94687901
就是可以分奇偶层,只有偶数层有效

//he!
#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
using namespace std;
typedef long long LL;
const int N=1e5+5;
int n,a[N],dep[N],D,S,C0,C1;
int bb[N*200];
vector<int> e[N];
void dfs(int u,int d) {
	dep[u]=d;
	if(e[u].empty()) D=d&1;
	for(auto v:e[u]) dfs(v,d^1);
}
int main() {
	cin>>n;
	FOR(i,1,n) cin>>a[i];
	int x;
	FOR(i,2,n) cin>>x,e[x].push_back(i);
	dfs(1,0);
	FOR(i,1,n)
		if(dep[i]==D) S^=a[i],++C0;
		else ++C1;
	LL ans=S ? 0 : 1LL*C0*(C0-1)/2+1LL*C1*(C1-1)/2;
	FOR(i,1,n) if(dep[i]==D) ++bb[S^a[i]];
	FOR(i,1,n) if(dep[i]!=D) ans+=bb[a[i]];
	cout<<ans<<endl;
}

2018ICPC南京D题 Country Meow

最小球覆盖?倒是先看出要用模拟退火 不会,就直接随机贪心
学会了,随机贪心要多rand几次哦

#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
using namespace std;
typedef long long LL;
struct Node {
	double x,y,z;
	Node operator-(Node v) {
		return (Node){x-v.x,y-v.y,z-v.z};
	}
	double operator~() {
		return sqrt(x*x+y*y+z*z);
	}
} a[105];
const double eps=1e-8,delta=0.5;
int n;
Node bst; double ans=1e18;
double qry(Node u) {
	double re=0;
	FOR(i,1,n) re=max(re,~(u-a[i]));
	return re;
}
void chk(double x,double y,double z) {
//	if(rand()&1) return;
	Node u=(Node){x,y,z};
	double cur=qry(u);
	if(cur<ans) {
		bst=u,ans=cur;
//		cerr << "(" << bst.x << ' ' << bst.y << ' ' << bst.z << "): " 
//		 	<< ans << endl;
	}
}
double solve() {
	bst=(Node){rand(),rand(),rand()};
	ans=qry(bst);
	Node &u=bst;
	for(double p=2e5;p>eps;p*=delta) {
		chk(u.x,u.y,u.z+p);
		chk(u.x,u.y,u.z-p);
		chk(u.x,u.y+p,u.z);
		chk(u.x,u.y-p,u.z);
		chk(u.x+p,u.y,u.z);
		chk(u.x-p,u.y,u.z);
	}
}
int main() {
	double aaa=1e18;
	cin>>n;
	FOR(i,1,n) cin>>a[i].x>>a[i].y>>a[i].z;
	int clc=clock();
	while(clock()-clc<CLOCKS_PER_SEC) solve(),aaa=min(ans,aaa);
	printf("%.10lf\n",aaa);
}

南京 G

数数题,分类数就好了。要么分奇偶然后打出表来插值也行

#include<bits/stdc++.h>
#define FOR(i,s,t) for(int i=s;i<=t;++i)
#define REP(i,t,s) for(int i=t;i>=s;--i)
#define int long long
using namespace std;
typedef long long LL;
namespace IO {
	char buf[1<<22],*p1=buf,*p2=buf;
	#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin))==p1?EOF:*p1++)
	//#define gc getchar()
	inline int rd() {
		int x=0; char c; while(isspace(c=gc));
		do x=x*10+(c^48); while(isdigit(c=gc));
		return x;
	}
} using IO::rd;
const int M=1e9+7;
const int I2=500000004,I3=333333336,I4=250000002,I6=166666668;
//#define M (LL)(1e18)
LL p1(LL x) {
	if(x<=0) return 0;
	return x*(x+1)/2%M;
}
LL p2(LL x) {
	if(x<=0) return 0;
	return x*(x+1)%M*(2*x+1)%M*I6%M;
}
LL p3(LL x) {
	if(x<=0) return 0;
	return 1LL*x*x%M*(x+1)%M*(x+1)%M*I4%M;
}
signed main() {
	int t,n;
	t=rd();
	FOR(tt,1,t) {
		n=rd();
//		n=tt;
		LL ans=(p2(n)+p1(n))*I2%M;
		if(n&1) {
			int k=n-2+1>>1;
			(ans+=(8*p3(k)%M+p1(k))*I3%M-2*p2(k)+2*p2(k)-p1(k))%=M;
		
		} else {
			int k=n-2>>1;
			(ans+=(8*p3(k)%M+p1(k))*I3%M+2*p2(k)+2*p2(k)+p1(k))%=M;
		}
	
		if(n&1) {
			n/=2;
			ans+=2*p2(n)+p1(n);
		}
		else {
			n/=2;
			ans+=2*p2(n)-p1(n);
		}
		printf("%lld\n",(ans%M+M)%M);
	}
}

在这里插入图片描述

内容概要:本文研究了计及碳排放的多微网电能交互分布式运行策略,提出了一种基于交替方向乘子法(ADMM)的优化方法,旨在实现多微电网系统在满足能源供需平衡的同时降低碳排放。文中构建了包含分布式电源、储能系统、可控负荷及碳排放约束的多微网协同优化模型,通过ADMM算法将全局优化问题分解为各微网子系统独立求解的子问题,实现分布式协同调度,在保障各微网自治性的同时兼顾系统整体的经济性与低碳性。研究通过Matlab代码完成了算法仿真,验证了所提策略在提升能源利用效率、减少碳排放、增强系统鲁棒性与可扩展性方面的有效性,为低碳化、去中心化的能源互联网运行提供了理论支持与实践参考。; 适合人群:具备电力系统分析、优化理论及Matlab编程基础的科研人员、电气工程及相关专业的研究生,以及从事智慧能源、分布式能源系统规划与运行的工程技术人员。; 使用场景及目标:①应用于多微电网系统的分布式能量管理与协同优化调度;②支持“双碳”目标下的低碳电网运行策略设计与政策评估;③为ADMM等分布式优化算法在能源系统中的工程化应用提供完整的模型构建、算法实现与仿真验证案例。; 阅读建议:读者应结合Matlab代码深入理解ADMM算法的迭代流程、拉格朗日函数构造与收敛条件设定,重点关注模型中碳排放因子的引入方式、变量分解机制与子问题求解过程,建议通过调整微网数量、碳价参数及通信拓扑结构进行多场景仿真,以深化对分布式协同机制与环保经济权衡关系的理解。
下载代码方式:https://pan.quark.cn/s/cc130f55eddd BUCK变换器,亦称为降压型转换器,在开关电源技术中属于一种基础电路拓扑,其核心功能在于实现从高电压到低电压的转换,并且在转换过程中确保输出端电压的稳定性。本文的核心内容集中在对BUCK变换器的运行机制进行剖析、阐释电流连续模式(CCM)与断续模式(DCM)之间的差异,并深入探讨这两种模式在稳态下的相互关系,同时研究BUCK变换器的交流等效电路模型以及电压与电流补偿回路的构建方法。BUCK变换器的原理示意图如图1所示,其显著特征在于输出电压值低于输入电压值,输出电流保持连续状态,而输入电流则呈现出脉动特性。变换器的工作过程可以划分为两个主要阶段:在第一个阶段,即开关管导通期间,电感元件负责储存能量,电流呈现出线性增长的趋势,并且同时向负载提供能量;在第二个阶段,即开关管截止期间,电感通过二极管实现能量的续流,电流则表现出线性递减的态势。依据电感元件的伏秒平衡原理,可以推导出涉及开关管占空比、电感元件电感量、输入电压以及输出电压之间关系的数学公式,这些公式对于深入理解和设计BUCK变换器具有关键性的指导意义。 接下来,文章对CCM和DCM两种模式进行了详细的比较分析。在CCM模式下,电感电流在整个开关周期内均保持连续的状态,而在DCM模式下,电感电流则会出现中断现象。确定BUCK变换器工作模式的关键依据是其电感电流纹波值与输出电流值相等这一边界条件。当电流纹波值等于零,即在整个开关周期内电感电流保持完全连续时,BUCK变换器被归类为CCM模式;相对地,若电流纹波值大于零,则表明变换器处于DCM模式;介于两者之间的情况则界定为CCM与DCM的过渡状态。 在DCM模式下,对BUCK...
源码链接: https://pan.quark.cn/s/ae09e867d64c S参数指的是散射参数,其英文全称为“Scattering-Parameter”。该参数用于表征电路网络中信号传输与反射的特性,是微波领域中衡量电路网络性能的核心指标。以二端口网络为例,比如单根传输线,其包含四个S参数,分别为S11、S12、S21和S22。其中,S11代表端口1的反射系数,S12代表端口1至端口2的反向传输系数,S21代表端口2至端口1的正向传输系数,而S22则表示端口2的反射系数。在高速电路设计领域,S参数是评估电路网络性能的关键依据。对于互易性网络,存在S12=S21的关系;对于对称性网络,满足S11=S22的条件;而对于无耗性网络,则有S11*S11+S21*S21=1,即网络不产生能量损耗,从端口1输入的能量要么被反射回端口1,要么被传输至端口2。在实际应用场景中,S参数能够用于评估电路网络的性能表现,例如,S11体现回波损耗,即有多少能量被反射回源端(Port1),该值越小越好,通常推荐S11<0.1,即-20dB。S21则反映插入损耗,即有多少能量被传输到目的端(Port2),该值越大越优,理想值为1,即0dB,传输效率越高,一般建议S21>0.7,即-3dB。此外,S参数还可用于判断电路网络的互易性与对称性。在高速电路设计过程中,这些参数具有显著意义,因为它们对电路网络的性能和稳定性具有直接影响。S参数是评估电路网络性能的核心指标,能够衡量电路网络的信号传输和反射能力,对于高速电路设计而言至关重要。关于Z参数和Smith圆图,Z参数属于阻抗参数,而Smith圆图是反射系数(以符号Γ表示)的极坐标图形。Smith圆图可用于评估电路网络的阻抗匹配状况...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值