对之前所学算法的一期复盘,包括一些运用不是很熟或者没看明白的知识点,然后就是一场cf和两个搜索题。

BFS

相比起深搜,广搜的时间可能更好,它主要还是一个队列的运用,先进先出,然后最主要的就是两个指针,head指现在要找的,tail指向根据现在要找的来找剩下的方向的值,个人建议使用结构体写,存放坐标位置和走到这一步的步数,然后还需要一个数组来存储走过的位置。先循环找完,在进行判断是否已经走到了目标位置。需要注意的一点是起始位置也是需要标记的。

KMP

我是有点不能理解它的一个判断以及求next数组的,后面看了两次动画演示,弄明白了。

首先next数组,它是一个当前元素与最开始的元素的最长的前后缀,注意next数组求的是字串的前后缀。

然后再比较就行,如果不相同,起始位置加上这个位置的next的值就行,避免了反复比较。时间上就快了很多。

cf

Problem - A - Codeforces

题目大意:这个国王可以往上下左右四个方向走也可以待在原地不动,问最少多少次可以到终点。

分析:开始看见这个题,。。。。。觉得纯纯一广搜模板题,可以嘎嘎秒,,,,,,结果它把我秒了,两个小时,,一道题,没出来,死磕广搜,老有问题,然后今天补题,看见了

 明白了,要贪心,,,,,结合了一下我写广搜时的感悟,先往离的远的那个坐标走,然后两个方向交替行走,因为它一个方向走了一次,下次就不能走这个方向,等一边到达后,走一步停一步,毕竟两点之间还是直线最短嘛。

至于用abs嘛,你看

 虽然四个点的坐标有正有负,但是它到原点的距离是相等的,取绝对值后会好算一点。

代码如下:

#include<stdio.h>
#include<math.h>
#include<string.h>
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int a,b;
        scanf("%d%d",&a,&b);
        a=abs(a);
        b=abs(b);
        int ans=0;
        if(abs(a-b)<=1)
        printf("%d\n",a+b);
        else{
            if(a>b)
            {
                int temp=a;
                a=b;
                b=temp;
            }
            ans+=2*a+1;
            b=b-a-1;
            ans+=2*b;
            printf("%d\n",ans);
        }
    }
    return 0;
}

Problem - B - Codeforces

题目大意:它有一批药,一盒药里面有k支药,但是这个药它有时间限制,在d个时间内必须用完,否则就要扔掉,它一共有n个人需要打这个药,每个人可以等待的时间是w,而且它每个人来的时间是递增的,问最少需要多少盒药。

分析:最少需要多少盒药它就是一个典型的贪心,也就是说我目前没打针的第一个人来的时候的时间加上人可以等待的时间w加上药可以存放的时间d,然后往后推,只要它后面的人来的时间不大于我目前没打针的第一个人来的时候的时间加上人可以等待的时间w加上药可以存放的时间d并且满足这一盒药的最大支数k,那么这就用一盒药。

 昨天打的时候根本就没有看第二题,觉得第二题的分比第一题高,就死磕了第一题,,,,,结果今天补题写第二题直接秒。

代码如下:

#include<stdio.h>
#include<math.h>
#include<string.h>
int a[200005];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,k,d,w;
		scanf("%d%d%d%d",&n,&k,&d,&w);
		for(int i=0;i<n;i++)
		scanf("%d",&a[i]);
		int sum=a[0]+d+w;
		int c=1;
		int j=1;
		for(int i=1;i<n;i++)
		{
			if(a[i]<=sum&&c<k)
			{
				c++;
			}
			else{
				c=1;
				j++;
				sum=a[i]+d+w;
			}
		}
		printf("%d\n",j);
	}
}

Problem - C - Codeforces

题目分析:

这个题目熬了挺久的,我开始是将n个数的1~n的和直接存放下来,然后直接找,但是纯暴力它也爆时间,不行啊不行。然后请教了学长,然后在学长的帮助下开始找规律。

1,可以发现对于奇数而言它的累加和除以它本身都是等于0的,对于偶数而言它的累加和除以它本身等于它本身的一半,所以我最先想到的是奇偶分判。

2,首先要搞清楚一件事就是这个数能不能根据它的力回到0区,只有两种可能,要么它第一次经过0区的时候就刚好到了0区,要么它第二次经过0区的时候刚好到达了0区,后面继续转也都是重复没有什么别的区别。

3,对于目前我所判断的数而言,如果超过了现在的i的一半的话那就没机会了就直接break,这是根据上面的规律得出来的;对于偶数而言((i/2)%n*(i+1)%n==t)表示的就是它第一次经过0区的时候就刚好到了0区的情况,((i/2)%n*(i+1)%n+n==t)表示的是它第二次经过0区的时候刚好到达了0区的情况,奇数同理。

代码如下:

#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        long long  n,x,p;
        scanf("%lld%lld%lld",&n,&x,&p);
        long long  t=n-x;
       int  f=0;
        for(int i=1;i<=p;i++)
        {
            if(i/2>n+1)
            break;
            if(i%2==0)
            {
                if(((i/2)%n*(i+1)%n==t)||((i/2)%n*(i+1)%n+n==t))
                {
                    f=1;
                    break;
                }
            }
            else{
                if((i%n*((i+1)/2)%n+n==t)||(i%n*((i+1)/2)%n==t))
                {
                    f=1;
                    break;
                }
            }
        }
        if(f)
        printf("Yes\n");
        else 
        printf("No\n");
    }
    return 0;
}

但是学长给了我一个新思路,我原称之为有技巧的暴力求解,大致思路其实差不多,我上面也说了这个数能不能根据它的力回到0区,只有两种可能,要么它第一次经过0区的时候就刚好到了0区,要么它第二次经过0区的时候刚好到达了0区,后面继续转也都是重复没有什么别的区别。就是在两倍的转盘的盘数和最大力值之间取两两值之间更小的那个数作为结束条件(其实我觉得“两倍的转盘的盘数”也可以换为目前的盘区到0盘区的距离加上转盘的盘数),然后从1开始持续累加,累加一次对对盘数也求一次余,如果余数为0,那就说明能到达0扇区。看见这个思路的时候我感觉打开了新世界。

简单搜索&&进阶搜索 - Virtual Judge

分析:

这是一道广搜模板题,虽然以前做的都是二维的,但是无论是二维还是三维,它的一个最基本的思路是一样的。

代码如下:

#include<stdio.h>
#include<math.h>
#include<string.h>
char a[32][32][32];
int l,r,c,l1,r1,c1;
int b[6][3]={{0,0,-1},{0,0,1},{-1,0,0},{1,0,0},{0,1,0},{0,-1,0}};
int book[32][32][32];

struct mg
{
	int x;
	int y;
	int z;
	int s;
}map[27000];



void bfs()
{
	int tail=1,head=1;
	map[tail].x=l1;
	map[tail].y=r1;
	map[tail].z=c1;
	map[tail].s=0;
	book[l1][r1][c1]=1;
	tail++;
	while(head<tail)
	{
		for(int i=0;i<6;i++)
		{
			int nx,ny,nz;
			nx=map[head].x+b[i][0];
			ny=map[head].y+b[i][1];
			nz=map[head].z+b[i][2];
			if(nx<0||nx>=l||ny<0||ny>=r||nz<0||nz>=c)
			continue;
			if(!book[nx][ny][nz]&&a[nx][ny][nz]!='#')
			{
				book[nx][ny][nz]=1;
				map[tail].x=nx;
				map[tail].y=ny;
				map[tail].z=nz;
				map[tail].s=map[head].s+1;
				tail++;
			}
			if(a[nx][ny][nz]=='E')
			{
				printf("Escaped in %d minute(s).\n",map[tail-1].s);
				return;
			}
		}
		head++;
	}
	printf("Trapped!\n");
}

int main()
{
	scanf("%d%d%d",&l,&r,&c);
	while(l!=0&&r!=0&&c!=0)
	{
		for(int i=0;i<l;i++)
		{
			for(int j=0;j<r;j++)
		{
			scanf("%s",a[i][j]);
		}
		}
		for(int i=0;i<l;i++)
		for(int j=0;j<r;j++)
		for(int k=0;k<c;k++)
		{
			book[i][j][k]=0;
			if(a[i][j][k]=='S')
			{
				l1=i;
				r1=j;
				c1=k;
			}
		}
		bfs();
		scanf("%d%d%d",&l,&r,&c);
	}
}

https://vjudge.net/contest/547627#problem/C

分析:

这个题目其实也很好想,它反正在Long long的范围内,就算是遍历也要不了多久,那就遍历。

首先,它的第一位数肯定是1,那么对于1而言,它可以延申出10或者11,而对于10而言它可以延申出101,100...........一直推下去,它就有点像二叉树的遍历,一直找,直到找到那个数,但是它找到了或者它找成了负数就不能找了,这就是限制条件。

代码如下:

#include<stdio.h>
#include<math.h>
#include<string.h>
long long k=1e19+2;
int n,f;
long long mm;
void ss(long long m)
{
	if(f||m<0)
	return;
	if(m%n==0)
	{
		f=1;
		mm=m;
		return;
	}
	ss(m*10);
	ss(m*10+1);
}

int main()
{
	scanf("%d",&n);
	while(n!=0)
	{
		f=0;
		ss(1);
		printf("%lld\n",mm);
		scanf("%d",&n);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值