Comet OJ - Contest #14

正题

      我好菜啊第二题都可以调40分钟。

      Portal

      A

      这题很简单,暴力即可。

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

int n;
long long a,b,r;

int main(){
	scanf("%d %lld %lld %lld",&n,&a,&b,&r);r*=r;
	long long x,y;
	int tot=0;
	for(int i=1;i<=n;i++){
		scanf("%lld %lld",&x,&y);
		if((x-a)*(x-a)+(y-b)*(y-b)<=r) tot++;
 	}
 	printf("%d\n",tot);
}

      B

      这题好烦啊,脑子非常乱,主要的做法就是找到一个三号点看一下最前面的两个点位置在哪里,最大化[2,3]两点的距离,或者找到一个四号点,看一下最前面的三个点在哪里,或者最大化[1,2]的距离,具体自己看看吧,写麻烦了。

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

const int N=1000010;
int n,T;
char s[N];
int last[N][4],pre[N][4],ans;

int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		scanf("%s",s+1);ans=-1;
		last[0][0]=last[0][1]=last[0][2]=last[0][3]=0;
		pre[n+1][0]=pre[n+1][1]=pre[n+1][2]=pre[n+1][3]=0;
		for(int i=1;i<=n;i++){
			last[i][0]=last[i-1][0];last[i][1]=last[i-1][1];
			last[i][2]=last[i-1][2];last[i][3]=last[i-1][3];
			if(s[i]=='p' && !last[i][0]) last[i][0]=i;
			else if(s[i]=='i' && !last[i][1] && last[i][0]) last[i][1]=i;
			else if(s[i]=='n' && !last[i][2] && last[i][1]) last[i][2]=i;
			else if(s[i]=='k' && !last[i][3] && last[i][2]) last[i][3]=i;
		}
		for(int i=n;i>=1;i--){
			pre[i][0]=pre[i+1][0];pre[i][1]=pre[i+1][1];
			pre[i][2]=pre[i+1][2];pre[i][3]=pre[i+1][3];
			if(s[i]=='p' && !pre[i][0] && pre[i][1]) pre[i][0]=i;
			else if(s[i]=='i' && !pre[i][1] && pre[i][2]) pre[i][1]=i;
			else if(s[i]=='n' && !pre[i][2] && pre[i][3]) pre[i][2]=i;
			else if(s[i]=='k' && !pre[i][3]) pre[i][3]=i;
		}
		for(int i=1;i<=n;i++) 
			if(s[i]=='i' && last[i][0] && pre[i][2]) ans=max(ans,max(i-last[i][0]-1,pre[i][2]-i-1));
			else if(s[i]=='n' && last[i][1] && pre[i][3]) ans=max(ans,max(i-last[i][1]-1,pre[i][3]-i-1));
		printf("%d\n",ans);
	}
}

      C

      要是考场上没想出来就亏大了,首先我们考虑加入一个区间会使得在l这个位置上有一个开头,在r+1位置上会多出来一个开头,并且把[l,r+1]这段的所有开头都去掉,所以我们把一个区间画成一条[l,r+1]的线段和l,r+1两个黑点,那么最后的权值就是从上往下看,黑点的个数,除了第n+1位,注意,一开始就有询问[1,n]。那么一个黑点产生贡献当且仅当不选那些比它晚并且覆盖它的询问。容易发现暴力即可。

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

int n,m;
long long ans=1;
struct interval{
	int x,y;
	long long t1,t2;
}p[2010];
const long long mod=20050321;

int main(){
	scanf("%d %d",&n,&m);
	p[0].t1=1;p[0].x=1;
	long long tot=1;
	for(int i=1;i<=m;i++){
		scanf("%d %d",&p[i].x,&p[i].y);p[i].y++;
		(ans+=tot)%=mod;p[i].t1=tot;
		if(p[i].y<=n) (ans+=tot)%=mod,p[i].t2=tot;
		for(int j=0;j<i;j++){
			if(p[j].x<p[i].x || p[i].y<p[j].x) (ans+=p[j].t1)%=mod,(p[j].t1*=2)%=mod;
			if(p[j].y<p[i].x || p[i].y<p[j].y) (ans+=p[j].t2)%=mod,(p[j].t2*=2)%=mod;
		}
		(tot*=2)%=mod;
		printf("%lld\n",ans);
	}
}

      D

      首先考虑不断加入一个区间,并且把它覆盖,区间的交的和是O(n)的,考虑一次加入最多新产生两个区间就可以了。

      考虑把询问按右端点时间从小到大排序。

      我们对于一个每一个区间的交,记录一下上次覆盖这个位置是什么时候,单点加就好了,在那个时间减去原本的贡献,在这个时间加上新的贡献就好了,容易证明这个是正确的。

      可惜的就是第二题花太多时间了导致这一题晚了8分钟AC。

#include<bits/stdc++.h>
#define ls now<<1
#define rs now<<1|1
using namespace std;

const int N=500010;
struct interval{
	int x,y,c,id;
	bool operator<(const interval q)const{
		return y<q.y;
	}
}p[N],X,Y;
set<interval> S;
set<interval>::iterator it;
long long sum[N*3];
struct ques{
	int x,y,id;
	bool operator<(const ques q)const{
		return y<q.y;
	}
}q[N];
long long ans[N];
int n,m,Q;

void add(int now,int x,long long t,int l,int r){
	sum[now]+=t;
	if(l==r) return ;
	int mid=(l+r)/2;
	if(x<=mid) add(ls,x,t,l,mid);
	else add(rs,x,t,mid+1,r);
}

long long get_sum(int now,int x,int y,int l,int r){
	if(x==l && y==r) return sum[now];
	int mid=(l+r)/2;
	if(y<=mid) return get_sum(ls,x,y,l,mid);
	else if(mid<x) return get_sum(rs,x,y,mid+1,r);
	else return get_sum(ls,x,mid,l,mid)+get_sum(rs,mid+1,y,mid+1,r);
}

int main(){
	scanf("%d %d %d",&n,&m,&Q);
	for(int i=1;i<=n;i++) scanf("%d %d %d",&p[i].x,&p[i].y,&p[i].c);
	for(int i=1;i<=Q;i++) scanf("%d %d",&q[i].x,&q[i].y),q[i].id=i;
	sort(q+1,q+1+Q);
	int now=0;
	S.insert((interval){1,m,0,0});
	for(int i=1;i<=Q;i++){
		while(now<q[i].y){
			now++;
			it=S.lower_bound((interval){0,p[now].x,0,0});
			while(it!=S.end()){
				X=*it;
				if(p[now].y<X.x) break;
				if(X.x<=p[now].x && p[now].y<=X.y){
					S.erase(it);
					if(X.y>p[now].y) S.insert((interval){p[now].y+1,X.y,X.c,X.id});
					if(X.x<p[now].x) S.insert((interval){X.x,p[now].x-1,X.c,X.id});
				}
				else if(p[now].x<=X.x && X.y<=p[now].y) S.erase(it);
				else{
					S.erase(it);
					if(X.x<p[now].x) S.insert((interval){X.x,p[now].x-1,X.c,X.id});
					else S.insert((interval){p[now].y+1,X.y,X.c,X.id});
				}
				if(X.id) add(1,X.id,-1ll*X.c*(min(p[now].y,X.y)-max(p[now].x,X.x)+1),1,n);
				add(1,now,1ll*p[now].c*(min(p[now].y,X.y)-max(p[now].x,X.x)+1),1,n);
				it=S.lower_bound((interval){0,p[now].x,0,0});
			}
			S.insert((interval){p[now].x,p[now].y,p[now].c,now});
		}
		ans[q[i].id]=get_sum(1,q[i].x,q[i].y,1,n);
	}
	for(int i=1;i<=Q;i++) printf("%lld\n",ans[i]);
}

      E

      这题就很简单了,直接缩点DAG上更新答案就可以了。

      只是别忘了Tarjan要用tf标记。

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

const int N=200010,M=500010;
struct edge{
	int y,next,c;
}s[M];
int first[N],n,m,mmin[N],mmax[N],d1[N],d2[N],T,dfn[N],low[N],op=0,where[N],ans[N],in[N];
int sta[N],top=0,q,len;
bool tf[N];
queue<int> Q;
vector<edge> E[N];
void ins(int x,int y,int c){s[++len]=(edge){y,first[x],c};first[x]=len;}
void inss(int x,int y,int c){E[x].push_back((edge){y,0,c});in[y]++;}

void Tarjan(int x){
	low[x]=dfn[x]=++op;
	sta[++top]=x;tf[x]=true;
	for(int i=first[x];i!=0;i=s[i].next) {
		int y=s[i].y;
		if(!dfn[y]) Tarjan(y),low[x]=min(low[x],low[y]);
		else if(tf[y]) low[x]=min(low[x],dfn[y]);
	}
	if(low[x]==dfn[x]){
		d1[++T]=mmin[T]=1e9,d2[T]=mmax[T]=0;ans[T]=-1e9;
		while(1){
			int now=sta[top];top--;
			where[now]=T;tf[now]=false;
			if(now==x) break;
		}
	}
}

void Top_sort(){
	Q.push(where[1]);
	while(!Q.empty()){
		int x=Q.front();Q.pop();
		for(int i=0;i<E[x].size();i++){
			int y=E[x][i].y,c=E[x][i].c;
			ans[y]=max(ans[y],max(max(d2[y],c)-mmin[x],mmax[x]-min(d1[y],c)));
			ans[y]=max(ans[y],max(d2[y]-c,c-d1[y]));
			ans[y]=max(ans[y],max(ans[x],0));
			mmax[y]=max(mmax[y],max(c,mmax[x]));
			mmin[y]=min(mmin[y],min(c,mmin[x]));
			in[y]--;
			if(!in[y]) Q.push(y);
		}
	}
}

int main(){
	scanf("%d %d %d",&n,&m,&q);
	int x,y,c;ans[0]=-1e9;
	for(int i=1;i<=m;i++){scanf("%d %d %d",&x,&y,&c);ins(x,y,c);};
	Tarjan(1);
	for(x=1;x<=n;x++) if(dfn[x])
		for(int i=first[x];i!=0;i=s[i].next) 
			if(where[s[i].y]!=where[x]) inss(where[x],where[s[i].y],s[i].c);
			else d1[where[x]]=mmin[where[x]]=min(mmin[where[x]],s[i].c),d2[where[x]]=mmax[where[x]]=max(mmax[where[x]],s[i].c),ans[where[x]]=max(ans[where[x]],mmax[where[x]]-mmin[where[x]]);
	Top_sort();
	while(q--){
		scanf("%d",&x);
		if(ans[where[x]]==-1e9) printf("-1\n");
		else printf("%d\n",ans[where[x]]);
	}
}

      F

      有两种思路,一种就是按题解所说的,用一棵可持久化线段树优化建边,在开始的时候加入一个原节点,在结束的时候加入一个无用的节点就可以了,然后剩下的就是Tarjan找割点。

      我的想法就是把一条横线段看成[r,x]-[l+n,x],然后一个竖线段相当于向[x,l]-[x+n,r]的横线段连边,具体就是建两棵KDT就可以了,时间复杂度垃圾了一些O(n\sqrt 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、付费专栏及课程。

余额充值