AtCoder Grand Contest 018

A - Getting Difference

裴蜀定理

#include<bits/stdc++.h>
using namespace std;

int n,k;

int gcd(int x,int y){
	return y==0?x:gcd(y,x%y);
}

int main(){
	int x,ans=0,mmax=0;
	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&x),ans=gcd(ans,x),mmax=max(mmax,x);
	printf(k%ans==0 && k<=mmax?"POSSIBLE\n":"IMPOSSIBLE\n");
}

B - Sports Festival

考虑每次删掉最大的即可,一直删完,中间肯定出现了最小值。

#include<bits/stdc++.h>
using namespace std;

const int N=310;
int n,m,a[N][N],tot[N],p[N];
bool tf[N];

int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)	
			scanf("%d",&a[i][j]);
		tot[a[i][1]]++;
		p[i]=1;
	}
	int ans=1e9;
	for(int i=1;i<=m;i++){
		int mmax=0;
		for(int j=1;j<=m;j++) mmax=max(mmax,tot[j]);
		ans=min(ans,mmax);
		int pos=0;
		for(int j=1;j<=m;j++) if(tot[j]==mmax){pos=j;break;}
		tf[pos]=true;
		for(int j=1;j<=n;j++){
			while(p[j]<=m && tf[a[j][p[j]]]){
				tot[a[j][p[j]]]--;
				p[j]++;
				tot[a[j][p[j]]]++;
			}
		}
	}
	printf("%d\n",ans);
}

C - Coins

智商题
考虑按照 A i − B i A_i-B_i AiBi给他们排序,如果已经选出了 Z Z 个点贡献 C i C_i Ci。剩下的 X + Y X+Y X+Y个点中,前 X X X个贡献的肯定是 A i A_i Ai,后 Y Y Y个肯定选 B i B_i Bi
那么我们枚举分界点,从前面选 X X X个出来,从后面选 Y Y Y个出来,直接用堆维护就可以了。

#include<bits/stdc++.h>
using namespace std;

const int N=100010;
struct node{	
	int a,b,c;
	bool operator<(const node&q)const{
		return a-b>q.a-q.b;
	}
}s[N];
priority_queue<int> A,B;
long long tota,totb,tb[N];
int X,Y,Z,n;

void insa(int x){
	A.push(-x);tota+=x;
	if(A.size()>X) tota+=A.top(),A.pop();
}

void insb(int x){
	B.push(-x);totb+=x;
	if(B.size()>Y) totb+=B.top(),B.pop();
}

int main(){
	scanf("%d %d %d",&X,&Y,&Z);n=X+Y+Z;
	long long tot=0;
	for(int i=1;i<=n;i++) scanf("%d %d %d",&s[i].a,&s[i].b,&s[i].c),tot+=s[i].c;
	sort(s+1,s+1+n);
	for(int i=1;i<=X;i++) insa(s[i].a-s[i].c);
	for(int i=n;i>=X+1;i--) insb(s[i].b-s[i].c),tb[i]=totb;
	long long ans=tot+tota+totb;
	for(int i=X+1;i<=n-Y;i++){
		insa(s[i].a-s[i].c);
		ans=max(ans,tot+tota+tb[i+1]);
	}
	printf("%lld\n",ans);
}

D - Tree and Hamilton Path

答案的上界很容易分析:
如果一条边两边的点数相同,那么就会被计算 n − 1 n-1 n1次。
如果不同,那么就是较小的一边点数 ∗ 2 *2 2
这个上界在 存在一条边使得两边点数都是 n 2 \frac n 2 2n的时候 会达到。
考虑在重心开始走欧拉回路就可以了。
否则就找一条重心相连的最短边减去就可以了,因为走的是一条欧拉通路。

#include<bits/stdc++.h>
using namespace std;

const int N=100010;
struct edge{
	int y,nex,c;
}s[N<<1];
int first[N],len=0,n,sz[N],mmin[N],pos;
bool tf=false;
long long ans=0;

void ins(int x,int y,int c){
	s[++len]=(edge){y,first[x],c};first[x]=len;
}

void dfs(int x,int fa){
	sz[x]=1;
	int mmax=0;
	for(int i=first[x];i!=0;i=s[i].nex) if(s[i].y!=fa){
		dfs(s[i].y,x);
		sz[x]+=sz[s[i].y];
		mmax=max(mmax,sz[s[i].y]);
		if(sz[s[i].y]*2==n) ans-=s[i].c,tf=true;
		ans+=2ll*s[i].c*min(sz[s[i].y],n-sz[s[i].y]);
	}
	if(max(mmax,n-sz[x])*2<=n) pos=x;
}

int main(){
	scanf("%d",&n);
	int x,y,c;
	memset(mmin,63,sizeof(mmin));
	for(int i=1;i<n;i++){
		scanf("%d %d %d",&x,&y,&c),ins(x,y,c),ins(y,x,c);
		mmin[x]=min(mmin[x],c);
		mmin[y]=min(mmin[y],c);
	}
	dfs(1,0);
	if(tf) printf("%lld\n",ans);
	else printf("%lld\n",ans-mmin[pos]);
}

E - Sightseeing Plan

考虑在中间这个矩形计算答案。
观察到: ∑ i = x 1 x 2 ∑ j = y 1 y 2 ( i + j i ) = ( x 2 + 1 + y 2 + 1 x 2 + 1 ) − ( x 2 + 1 + y 1 x 2 + 1 ) − ( x 1 + y 2 + 1 x 1 ) + ( x 1 + y 1 x 1 ) \sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y_2}\binom {i+j}{i}=\binom{x_2+1+y_2+1}{x_2+1}-\binom{x_2+1+y_1}{x_2+1}-\binom{x_1+y_2+1}{x_1}+\binom{x_1+y_1}{x_1} i=x1x2j=y1y2(ii+j)=(x2+1x2+1+y2+1)(x2+1x2+1+y1)(x1x1+y2+1)+(x1x1+y1)
发现一个点到一个矩形的路径条数可以转化为到四个点的路径条数,那么现在就变为四个点经过一个矩形到四个点的路径条数了。
枚举一对点,变成单点经过矩阵到单点的方案数,经过矩阵时还要乘上经过矩阵的点数,考虑在入矩阵和矩阵的两个点差分,所以只需要在矩阵上的每一个点计算出经过该点的路径条数,乘上该点的差分贡献即可。

#include<bits/stdc++.h>
using namespace std;

const int N=2000010,mod=1000000007;
int X[6],Y[6],fac[N],inv[N];

int ksm(int x,int t){
	int tot=1;
	while(t){
		if(t&1) tot=1ll*tot*x%mod;
		x=1ll*x*x%mod;
		t/=2;
	}
	return tot;
}

int C(int x,int y){
	if(x<0 || y<0) return 0;
	return 1ll*fac[x+y]*inv[x]%mod*inv[y]%mod;
}

int calc(int x1,int y1,int x2,int y2){
	int ans=0;
	for(int i=X[2];i<=X[3];i++){
		ans=(ans+mod-1ll*(Y[2]+i)*C(i-x1,Y[2]-y1-1)%mod*C(x2-i,y2-Y[2])%mod)%mod;
		ans=(ans+1ll*(Y[3]+i+1)*C(i-x1,Y[3]-y1)%mod*C(x2-i,y2-Y[3]-1))%mod;
	}
	for(int i=Y[2];i<=Y[3];i++){
		ans=(ans+mod-1ll*(X[2]+i)*C(X[2]-x1-1,i-y1)%mod*C(x2-X[2],y2-i)%mod)%mod;
		ans=(ans+1ll*(X[3]+i+1)*C(X[3]-x1,i-y1)%mod*C(x2-X[3]-1,y2-i))%mod;
	}
	return ans;
}

int main(){
	fac[0]=1;for(int i=1;i<N;i++) fac[i]=1ll*fac[i-1]*i%mod;
	inv[N-1]=ksm(fac[N-1],mod-2);for(int i=N-2;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
	for(int i=0;i<6;i++) scanf("%d",&X[i]);
	for(int i=0;i<6;i++) scanf("%d",&Y[i]);
	X[0]--;Y[0]--;X[5]++;Y[5]++;
	int ans=0;
	for(int a=0;a<2;a++)
		for(int b=0;b<2;b++)
			for(int c=0;c<2;c++)
				for(int d=0;d<2;d++){
					if((a+b+c+d)&1) ans=(ans+mod-calc(X[1-a],Y[1-b],X[4+c],Y[4+d]))%mod;
					else ans=(ans+calc(X[1-a],Y[1-b],X[4+c],Y[4+d]))%mod;
				}
	printf("%d\n",ans);
}

F - Two Trees

神仙题
一点头绪都没有,做法是生生构造出来的。
建立一个超级源,向两棵树的根
首先一个点的度数若在两棵树中的奇偶性不同,那么无解。
否则给度数为奇数的点跨越两棵树连一条边,跑欧拉回路,偶数度的点标为 0 0 0,奇数度的点若连边正向通过,那么标为 1 1 1,否则标为 − 1 -1 1
证明考虑每一个点在的所有环,只有一个会经过父亲与其这条边,并对子树造成 + 1 / − 1 +1/-1 +1/1的贡献,否则贡献为 0 0 0

#include<bits/stdc++.h>
using namespace std;

const int N=200010;
struct edge{
	int y,nex;
	bool tf;
}s[1000010];
int first[N],len=1,n,las=0,a[N];
bool d[N];

void ins(int x,int y){
	s[++len]=(edge){y,first[x]};first[x]=len;
	s[++len]=(edge){x,first[y]};first[y]=len;
	d[x]^=1;d[y]^=1;
}

void dfs(int x){
	int y;
	while(first[x]!=0){
		if(!s[first[x]].tf){
			y=s[first[x]].y;
			s[first[x]].tf=true;s[first[x]^1].tf=true;
		}
		else y=-1;
		first[x]=s[first[x]].nex;
		if(y!=-1) dfs(y);
	}
	if(las!=0){
		if(abs(x-las)==n){
			if(x<las) a[x]=-1;
			else a[las]=1;
		}
	}
	las=x;
}

int main(){
	scanf("%d",&n);
	int x;
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		if(x==-1) ins(2*n+1,i);
		else ins(x,i);
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		if(x==-1) ins(2*n+1,n+i);
		else ins(n+x,n+i);
	}
	bool tf=true;
	for(int i=1;i<=n;i++) if(d[i]^d[n+i]){tf=false;break;}
	else if(d[i]) ins(i,n+i);
	if(!tf) printf("IMPOSSIBLE\n");
	else{
		printf("POSSIBLE\n");
		dfs(2*n+1);
		for(int i=1;i<=n;i++) printf("%d ",a[i]);printf("\n");
	}
}
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值