2022-01-10 每日打卡:难题精刷

2022-01-10 每日打卡:难题精刷

写在前面

“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,所刷题目共三个来源:之前没做出来的 ;Leetcode中等,困难难度题目; 周赛题目;某个专题的经典题目,所有代码已AC。每日1-3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。

POJ 2456 Aggressive cows

在这里插入图片描述
并没有好的算法来排布,最开始想的是递归二分,每次将一只牛放在区间最接近中位数的位置,也许思路是对的,但超时了。看不见测试用例,这里记录一下双指针(尺取)法:

需要枚举的题几乎都可以使用二分法,即不断逼近以确定答案,只需要将第一次的取值确定好即可。
譬如这个题可以发现距离的上界是a[n-1]- a[0] /(牛的个数-1),再超过这个距离一定放不下。
那么就进行不断二分,设下界为1,上界为这个距离的两倍,得出的一个距离就是该距离。然后二分。

	#include <algorithm>
	#include <cmath>
	#include <iostream>
	using namespace std;
	int a[100005];
	int n,m,i,j,f,l,mid;
	bool check(int mm)
	{
		int i,s=1,k=0;
		for(i=1;i<n;i++)
		{
			if(mm+a[k]<=a[i])
			{
				k=i;
				s++;
			}
			if(s==m)
			break;
		}
		if(s<m)return false;
		return true; 
	}
	int main()
	{	
		scanf("%d%d",&n,&m);
		for(i=0;i<n;i++)
		scanf("%d",&a[i]);
		sort(a,a+n);
	    int total = ceil(((a[n - 1] - a[0]) / (double)(m-1)));
	    f=1,l=total*2-1;
		while(f<=l)//二分 
		{
			mid=(f+l)/2;
	        // cout<<f<<l<<mid;
			if(check(mid))
			f=mid+1;
			else
			l=mid-1;
		}
		printf("%d\n",l);
	}                                                                                                                                                                                                                                                                                                                                         

POJ 2406 Power Strings

在这里插入图片描述
KMP求最小循环节,首先要理解next数组的含义:next[i]表示前面长度为i的子串中,前缀和后缀相等的最大长度。
在这里插入图片描述
可以发现:

  • 不相同,模式串后移,相当于模式串的指针前移,在这个题中最开始的一个串的表现就是前指针,也就是从开头就匹配的模式串不动(移回来了),后指针++
  • 相同,前后指针一起移动

前指针移动到什么位置呢?在KMP算法中,移动到 部分对应匹配值 的下一位就可以,也就是我们说的next数组。所以主要是需要求出next数组:
在这里插入图片描述
求法就是dp,共有以下转移条件:

  • 开始or不相等:移动指针到匹配个数,赋值next
  • 相等:移动指针,赋值next
	#include<cmath>
	#include<cstdio>
	#include<string>
	#include<iostream>
	#include<algorithm>

	using namespace std;
	typedef unsigned long long ll;
	typedef long long LL;
	char s[1000000+10];
	int nexts[1000000+10];
	int len;
	void get_next()
	{
	    int i,j;
	    j=nexts[0]=-1;
	    i=0;
	    while(i<len)
	    {
	        while(-1!=j&&s[i]!=s[j]) j=nexts[j];
	        nexts[++i]=++j;
	    }
	}
	int main()
	{
	    while(~scanf("%s",s)&&s[0]!='.')
	    {
	        len=strlen(s);
	        get_next();
	        int ans=1;
	        if(len%(len-nexts[len])==0)
	             ans=len/(len-nexts[len]);
	        printf("%d\n",ans);
	    }
	}
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值