20161010的考试】noip模拟,崩的不要不要的(模拟题,two(three) pointer,模拟

本文解析了三项编程挑战,包括多项式求导模拟题、数列区间选择优化算法及树上三人追逐问题。通过多种解法展示算法设计思维,特别关注优化技巧与数据结构的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

……三道大水题……

三道题都写了……然而40’…………看来是要GG  QAQ

天天崩的我已经……无所畏惧QwQ

T1

关于x的多项式求导,就是个大模拟题…………我数组开小了

然后……嗯……

特判puts("0")的时候……顺手在main里面return puts("0");了……嗯……人造的RE0,稳得不行

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;	int n;
char s[MAXN];
char put[205][50];
int fu[205];
int main(){
	freopen("equation.in","r",stdin);
	freopen("equation.out","w",stdout);
	scanf("%s",s),n=strlen(s);
	long long xi=0,zhi=0;
	int cnt=0;
	int up_flag=0;
	int fu_flag=0;
	for(int i=0;i<n;++i){
		char cur=s[i];
		if(cur=='x'){
			zhi=1;
			if(!xi)	xi=1;	
		}
		if(cur=='^'){
			up_flag=1,zhi=0;
		}
		if(isdigit(cur)){
			if(up_flag)	zhi=zhi*10+cur-'0';
			else	xi=xi*10+cur-'0';
		}
		if(cur=='+'||i==n-1){
			if(zhi){
				fu[++cnt]=fu_flag? -1:1;
				if(zhi>1){
					if(zhi==2)	sprintf(put[cnt],"%lldx",xi*zhi);
					else	sprintf(put[cnt],"%lldx^%lld",xi*zhi,zhi-1);
				}
				else	sprintf(put[cnt],"%lld",xi*zhi);
			}
			xi=0,zhi=0,up_flag=0,fu_flag=0;
		}
		if(cur=='-'||i==n-1){
			if(zhi){
				fu[++cnt]=fu_flag? -1:1;
				if(zhi>1){
					if(zhi==2)	sprintf(put[cnt],"%lldx",xi*zhi);
					else	sprintf(put[cnt],"%lldx^%lld",xi*zhi,zhi-1);
				}
				else	sprintf(put[cnt],"%lld",xi*zhi);
			}
			xi=0,zhi=0,up_flag=0,fu_flag=1;
		}
	}
	if(!cnt)	return puts("0"),0;
	for(int i=1;i<=cnt;++i){
		if(i==1){
			if(fu[i]==-1)	printf("-%s",put[i]);
			else	printf("%s",put[i]);
		}
		else
			putchar(fu[i]==-1?'-':'+'),printf("%s",put[i]);
	}
	return 0;
}




T2

给一个数列,选取一个区间,使区间里数i的数量在(Li与Ri之间(闭区间

解一:naive地暴力……枚举左右端点,check是否合法 O(n*n*k)

解二:枚举左右端点,因为左右端点的移动只影响一个值是否合法 check可以优化成O(1) 于是O(n*n)

解三:枚举左端点,右端点随着左端点右移只会往右移动,于是是个O(n)的做法

解四:听说可以nlogn地乱搞

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#define MAXN 200005
#define INF 0x3f3f3f3f
using namespace std;	int n,k;
int a[MAXN];
int Min[MAXN],Max[MAXN];
int cnt1[MAXN],cnt2[MAXN];
int l,r;

int main(){
	freopen("survey.in","r",stdin);
	freopen("survey.out","w",stdout);

	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;++i)	scanf("%d",a+i),++cnt1[a[i]];
	for(int i=1;i<=k;++i)	scanf("%d%d",Min+i,Max+i);

	Min[0]=0,Max[0]=INF;

	for(int i=1;i<=k;++i)
		if(cnt1[i]<Min[i])	return puts("0"),0;

	for(int i=n;i;--i){
		--cnt1[a[i]];
		if(cnt1[a[i]]<Min[a[i]]){
			l=i,++cnt1[a[l]];
			break;
		}
	}
	
	cnt1[0]=cnt2[0]=1;
	long long ans=0;
	for(int i=1;i<=n;++i){
		--cnt1[a[i-1]],--cnt2[a[i-1]];
		while(l<n && cnt1[a[i-1]]<Min[a[i-1]])	++cnt1[a[++l]];
		if(cnt1[a[i-1]]<Min[a[i-1]])	break;
		while(r<n && cnt2[a[r+1]]<Max[a[r+1]])	++cnt2[a[++r]];
		
		printf("i = %d  l = %d  r = %d\n",i,l,r);
		ans+=max(0,r-l+1);
	}
	printf("%lld",ans);
	return 0;
}




T3

一棵树上有三个点s,p,q三个人分别从s,p,q三个点出发,对于每个三秒,在第一秒时s会走一步,第二秒p和q会向s所在的方向走一步,第三秒和第二秒相同

问pq与s相遇的最晚时间中,更早的那个是多久

思路:因为是棵树,所以s肯定不会走到p或q的后面去,所以可以理解成染色,s不能染pq,pq随便染,最后一个被pq染掉的且被s染过的节点就是答案

所以模拟一下bfs就好

然而因为懒得多写几个bfs直接开模拟,于是很多细节没有考虑到,debug了好久啊QwQ

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
#define MAXN 200005
#define INF 0x3f3f3f3f
using namespace std;	int n,p0,p1,p2;
struct t1{
	int to,nxt;
}edge[MAXN<<1];	int cnt_edge=0;
int fst[MAXN];
void addedge(int x,int y){
	edge[++cnt_edge].to=y;
	edge[cnt_edge].nxt=fst[x];
	fst[x]=cnt_edge;

	edge[++cnt_edge].to=x;
	edge[cnt_edge].nxt=fst[y];
	fst[y]=cnt_edge;
}

int col[MAXN],tim[MAXN];
int tag[MAXN];

const int MN3=MAXN*3;
int que[MN3],head,tail;
int in_que[MAXN];
int skp[MN3];

queue<int> q2;

int ans=0;
void bfs(){
	head=tail=0;
	que[tail++]=p0,que[tail++]=p1,que[tail++]=p2;
	memset(tim,INF,sizeof tim);
	memset(in_que,-1,sizeof in_que);
	tim[p1]=tim[p2]=0;
	int now;
	while(head^tail){
		if(skp[head]){
			++head;
			continue;
		}
		now=que[head++];
//		printf("now = %d\n",now);
		if(head==MN3)	head=0;
		if(col[now]==1){
			for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
				int aim=edge[tmp].to;
				if(col[aim])	continue;
				col[aim]=1;
				que[tail++]=aim;
				in_que[aim]=tail-1;
				if(tail==MN3)	tail=0;
			}
		}
		else{
			while(!q2.empty())	q2.pop();
			for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
				int aim=edge[tmp].to;
				if(col[aim]==1)	tag[aim]=1;
				if(col[aim]!=2){
					if(~in_que[aim])	skp[in_que[aim]]=1;
					q2.push(aim);
					tim[aim]=tim[now]+2;
					col[aim]=2;
				}
				else
					if(tim[now]+2<tim[aim])
						tim[aim]=tim[now]+2,q2.push(aim);
			}
			
			while(!q2.empty()){
				now=q2.front();
				q2.pop();
				for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
					int aim=edge[tmp].to;
					if(col[aim]==1)	tag[aim]=1;
					if(col[aim]!=2){
						que[tail++]=aim;
						if(~in_que[aim])
							skp[in_que[aim]]=1;
						if(tail==MN3)	tail=0;
						tim[aim]=tim[now]+1;
						col[aim]=2;
					}
					else
						if(tim[now]+2<tim[aim])
							tim[aim]=tim[now]+1,que[tail++]=aim;
				}
			}
		}
	}
}

int read_x,read_y;
int main(){
	freopen("track.in","r",stdin);
//	freopen("track.out","w",stdout);

	scanf("%d%d%d%d",&n,&p0,&p1,&p2);
	if(p0==p1||p0==p2)	return puts("0"),0;
	for(int i=1;i<n;++i)	
		scanf("%d%d",&read_x,&read_y),addedge(read_x,read_y);
	col[p1]=col[p2]=2;
	col[p0]=1;
	bfs();

//	for(int i=1;i<=n;++i)	printf(" %d  tag = %d   tim = %d\n",i,tag[i],tim[i]);

	for(int i=1;i<=n;++i)	if(tag[i])	ans=max(ans,tim[i]);
	printf("%d",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值