第九届湖南省省赛

题目为CSU 1328--1339

总结

不是我语死早就是出题人语死早

A



B

直接用链表就行,当时还傻乎乎的用线段树去做。

赛后打算用链表做时敲到一半突然发现。。。。链表已经忘得一干二净。。。。。。。。敲了半天

注意建立链表时头尾的处理,最好留空表头和表尾。

还有X,Y是指盒子的值不是盒子的位置。

-------------------------------------------------------------------------------------我是去你妹的分割线---------------------------------------------------------------------------------------

敲你妹的链表啊,好不容易敲完发现超时了,果然什么链表都去死才适合我,直接用两个个数组就就搞定了,才260ms有木有,算了,就当复习下链表

注意衔接细节就行了,像我一样神经大条的画个图把前驱后继都标上就不会漏了,还有就是x,y相邻时要注意处理

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int MAX=1111111;
int n,m;
bool flag;
long long sum;
int l[MAX];
int r[MAX];
int main()
{
	int ca=1;
	int i,j;
	int op;
	int x,y;
	int temp;
	int a,b;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(i=0;i<=n+1;++i)	//防止越界 
		{
			l[i]=i-1;
			r[i]=i+1;
		}
		flag=true;
		while(m--)
		{
			scanf("%d",&op);
			if(op==4)
			{
				flag=!flag;
			}
			else
			{
				scanf("%d%d",&a,&b);
				if(op==3)
				{
					if(l[a]==b)		//x,y相邻,特殊处理 //注意交换后,原来前驱的后继也要变,后继的前驱也是
					{
						r[b]=r[a];
						l[a]=l[b];
						r[l[b]]=a;
						l[b]=a;
						l[r[a]]=b;
						r[a]=b;
					}
					else if(r[a]==b)
					{
						r[a]=r[b];
						l[b]=l[a];
						r[l[a]]=b;
						l[a]=b;
						l[r[b]]=a;
						r[b]=a;
					}
					else
					{
						r[l[a]]=b;
						l[r[a]]=b;
						r[l[b]]=a;
						l[r[b]]=a;
						temp=l[a];
						l[a]=l[b];
						l[b]=temp;
						temp=r[a];
						r[a]=r[b];
						r[b]=temp;
					}
				}
				else if((op==1&&flag)||(op==2&&!flag))		//判断条件要设置对 
				{
					r[l[a]]=r[a];
					l[r[a]]=l[a];
					l[a]=l[b];
					r[a]=b;
					r[l[b]]=a;
					l[b]=a;
				}
				else
				{
					r[l[a]]=r[a];
					l[r[a]]=l[a];
					r[a]=r[b];
					l[a]=b;
					l[r[b]]=a;
					r[b]=a;	
				}
			}
		}
		sum=0;
		if(flag)
		{
			temp=r[0];
			for(i=1;i<=n;)
			{
				sum+=temp;
				temp=r[r[temp]];
				i+=2;
			}
		}
		else
		{
			temp=l[n+1];
			for(i=1;i<=n;)
			{
				sum+=temp;
				temp=l[l[temp]];
				i+=2;
			}
		}
		printf("Case %d: %lld\n",ca++,sum);
	}
	return 0;
}


C

尼玛,这代号也太抽象了吧,百思不得其解题意,结果突然看到长得和1.2.3一样。。。。。。就理解题意了

就是靠第四行的*位置来判断是1还是2还是3。读懂题意后就想去撞墙了。。。

D


E



F


G



H

很明显是线段树,结果前面几道卡了太多时间(再一次撞墙),来不及做

一开始想到为设最大高度的线段树,然后发现要各种离散化,看别人a得很快,所以就觉得不可能是这样做的。

赛后做时就立马想到解题思路了。。。。

先把每座桥的高度从小到大排序,然后设n的线段树,底部叶子节点保存的信息为每座桥被淹没的次数,其他节点为延迟标记,然后每次更新时对被覆盖的区间成段更新(用对应位置的桥高度进行二分比较查找),具体代码如下

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAX=int(1e8)+11;
const int M=int(1e5)+11;
#define ls l,mid,root<<1
#define rs mid+1,r,root<<1|1
int n,m,k;
int line[M<<3];
int arr[M];
int num;
int sum;
bool cmp(int x,int y)
{
	return x<y;
}
void build(int l,int r,int root)
{
	if(l==r)
	{
		line[root]=0;
		return ;
	}
	int mid=(l+r)>>1;
	build(ls);
	build(rs);
	line[root]=0;
}
void pushdown(int root)
{
	if(line[root]!=0)
	{
		line[root<<1]+=line[root];
		line[root<<1|1]+=line[root];
		line[root]=0;
	}
}
void update(int l,int r,int root,int low,int hig)
{
	if(low<=arr[l]&&hig>=arr[r])
	{
		line[root]++;
		return;
	}
	if(l==r)
	{
		return;<span style="white-space:pre">				</span>//注意递归出口的设置,会出现比最低的桥值低,比最高的桥值高的情况,在这里re了好几发。。。。。
	}                                              
	pushdown(root);
	int mid=(l+r)>>1;
	if(low<=arr[mid])
	{update(ls,low,hig);}
	if(hig>arr[mid])
	{update(rs,low,hig);}
}
void query(int l,int r,int root,int p)
{
	if(l==r)
	{
		if(line[root]>=k)
		{sum++;}
		return;
	}
	pushdown(root);
	int mid=(l+r)>>1;
	if(p<=mid)
	{query(ls,p);}
	else
	{query(rs,p);}
}
int main()
{
	int ca=1;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		int i,j;
		int hig,low;
		int last=1;;
		for(i=1;i<=n;++i)
		{scanf("%d",&arr[i]);}
		sort(arr+1,arr+n+1,cmp);<span style="white-space:pre">			</span>//sort排序时注意数组开头的结束位置,在这里wa了一发。。。果然是弱得一B
		num=1;
		build(1,n,1);
		while(m--)
		{
			scanf("%d%d",&hig,&low);
			update(1,n,1,last+1,hig);
			last=low;
		}
		sum=0;
		for(i=1;i<=n;++i)
		{
			query(1,n,1,i);
		}
		printf("Case %d: %d\n",ca++,sum);
	}
	return 0;
} 
/*
1 2 1
5
6 2
3 1
*/

此外还有一种简单的做法,直接开一个数组标记下淹没的起始和结束位置,然后扫一遍就行,和之前在bestcode做过的一道题一样

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAX=int(1e8)+11;
const int M=int(1e5)+11;
int n,m,k;
int arr[M];
int status[M];
bool cmp(int x,int y)
{
	return x<y;
}
int find(int l,int r,int v)
{
	if(v==1)
	{return 0;}		//初始水位为1,往前-1; 
	if(l==r)
	{
		return l;
	}
	int mid=(l+r)>>1;
	if(v<=arr[mid])
	{find(l,mid,v);}
	else
	{find(mid+1,r,v);}
}
int main()
{
	int ca=1;
	int i,j;
	int a,b;
	int last;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		for(i=1;i<=n;++i)
		{scanf("%d",&arr[i]);}
		sort(arr+1,arr+1+n,cmp);
		last=1;
		memset(status,0,sizeof(status));
		while(m--)
		{
			scanf("%d%d",&a,&b);
			status[find(1,n,last)+1]++;		//上次退潮高度已经被淹没,往后+1	 
			status[find(1,n,a)+1]--;		//即使处于涨潮高度仍被淹没,往后+1 
			last=b;
		}
		int sum=0;
		int temp=0; 
		for(i=1;i<=n;++i)
		{
			printf("status[%d]=%d\n",i,status[i]);
			temp+=status[i];
			if(temp>=k)
			{sum++;}
		}
		printf("Case %d: %d\n",ca++,sum);
	}
	return 0;
}
I



J

其实很简单,就是一开始不敢去尝试,还好之前有看过枚举的优化,枚举A,B就行了,把计算得到的C进行验证,还有一个是剪枝,A,B的最大值只能是1000,优化一下就行了,100msAC后在自喜,看到别人居然是4ms。。。。。我还是太弱了。。。。 

K



L

尼玛,题意没看清,数组开小了,结果就一直wa了3发!掩面而泣~po主去蹲角落了~~


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值