第三节-字符串、序列

这节难度很大,有很多处理方法都可以消化
第一题:oj里面的1085,题目是处理环状序列,主要知识点就是关于string的应用,一个是把字符串延长做法一个是关于取子串做法,需要做的是学习string

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	string s;
	scanf("%d",&t);
	while(t--)
	{
		cin>>s;
		string s2,smin;
		smin=s;
		int len=s.size();
		s+=s;
		for(int i=0;i<len;i++)
		{
			s2=s.substr(i,len);
			if(s2<smin) smin=s2;
		}
		cout<<smin<<endl;
	}
	return 0;
}

下一题是oj重复子序列1039问题
这个题难度很大,有一个重要知识点要记,序列自动机,以及为了方便序列自动机做出的改动

#include<bits/stdc++.h>
using namespace std;
#define N 100005
int main()
{
	int st[N][26];
	char a[N],b[N];
	while(scanf("%s%s",a+1,b)!=EOF)  //这个a+1处理技巧,目的是让序列自动机好用
	{
		int len=strlen(a+1);      //从1到len的意思
		for(int i=0;i<26;i++)st[len][i]=0; //最后一个位置什么也没有
		for(int i=len;i>0;i--)          //序列自动机,很重要思想,后面有很多事实上类似的处理
		{
			for(int j=0;j<26;j++)
			//保留上个位置状态
			st[i-1][j]=st[i][j];
			st[i-1][a[i]-'a']=i;
		}
		int ans=1;int l=strlen(b);int j=0;
		//int k=0;
		for(j=0;j<l;j++) {
			if(st[0][b[j]-'a']==0)break;
		}
		if(j<l) puts("-1");
		else
		{ 
			int i=0;          //a的下标是1,但是从0开始
			for(j=0;j<l;j++)
			{
				i=st[i][b[j]-'a'];
				if(i==0)
				{
					ans++;
					i=st[i][b[j]-'a'];
				}
			}
		}
		printf("%d\n",ans);
		/*while(j<l)
		{
			if(st[k][b[j]-'a']==0){
				//ans=-1;
				//cout<<"-1"<<endl;
				break;
			}
			else
			{
				j++;
				k=st[k][b[j]-'a']+1;
				if(k>=len)
				{
					k=0;ans+=1;
				}
			}
		}*/
		//if(j<l)puts("-1");
		//printf("%d\n",ans);
	}
	return 0;
}

第三题是1035出现连续字符串最大数目
此题是难题,主要方法有:前缀和
其中在最后的循环判断和ans的处理上出现问题,总结说就是细节分析情

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+3;
int st[N][26];
int main()
{
	int k;
	char s[N];
	while(scanf("%d%s",&k,s)!=EOF)
	{
		int len=strlen(s);
		for(int j=0;j<26;j++) st[0][j]=0;
		for(int i=0;i<len;i++)
		{
			for(int j=0;j<26;j++) st[i+1][j]=st[i][j];
			st[i+1][s[i]-'a']++;
		}
		int l=0,r=len,m;
		int ans=0;
		while(l<=r)
		{
			bool flag=0;
			int i=0;
			m=(l+r)>>1;
			for(;i+m<=len;i++)
			{
				if(st[i+m][s[i]-'a']-st[i][s[i]-'a']+k>=m&&st[len][s[i]-'a']-st[0][s[i]-'a']>=m)
				{
					flag=1;break;
				}
			}
		if(flag)
		{
			ans=m;l=m+1;
		}
		else r=m-1;
        }
		printf("%d\n",ans);
	}
	return 0;
}

第四题是1344 PIPI的字符串问题Ⅱ

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+3;
typedef unsigned long long ull;
const ull base=2333;
int main()
{
	char t[N],s[N];
	ull st[N];
    scanf("%s%s",s,t);
    	int n=strlen(t),m=strlen(s);   //t小s大
    	if(n>m)                //这个条件判断也很重要
		{ 
			puts("NO");return 0;
		}
    	//st[0]=s[0];
    	for(int i=1;i<=m;i++)
    	st[i]=s[i-1]+st[i-1]*base;   //重点就是关于这个东西,前缀和
    	ull ht=0,p=1;
    	for(int i=0;i<n;i++) p=p*base;  //基数
    	for(int i=0;i<n;i++)
    	ht=ht*base+t[i];              //计算综合与前缀和的区别
    	int ans=0;
    	for(int i=0;i+n<=m;i++)
    	{
    		if(st[i+n]-st[i]*p==ht)
    		{
    			ans++;
			}
		}
		if(ans>0)
		{
			printf("YES\n%d\n",ans);
		}
		else
		printf("NO\n");
	return 0;
}

第五题1345: PIPI的字符串问题Ⅲ
这个提说明前缀和还是没了解完

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+3;
typedef unsigned long long ull;
ull st1[N],st2[N];
ull base=2333;
ull p[N];
int main()
{
	char s[N];
	scanf("%s",s);
	int len=strlen(s);
	for(int i=1;i<=len;i++)
	st1[i]=st1[i-1]*base+s[i-1];
	for(int i=len;i>0;i--)
	st2[i-1]=st2[i]*base+s[i-1];
	p[0]=1;
	for(int i=1;i<=len;i++) p[i]=p[i-1]*base;
	int q,m,n;
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d %d",&m,&n);
	//	for(int i=0;i<m-n+1;i++) p=p*base;
		ull w,e;
		w=st1[n]-st1[m-1]*p[n-m+1],e=st2[m-1]-st2[n]*p[n-m+1];
		if(w==e) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

第六题1351小鱼比可爱
较为简单的一道题

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+3;
int main()
{
	int n;int a[N],b[N];
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	int stack[N];int top=-1;
	top++;
	stack[top]=n;     //站内存下标
	b[n]=0;   //最右边一定是0
	for(int i=n-1;i>0;i--)  //遍历n-1次
	{
		if(a[i]>=a[stack[top]])
		{
			while(a[i]>=a[stack[top]]&&top>=0) top--;
			if(top==-1)
			{
				b[i]=0;
				top++;
				stack[top]=i;
			}
			else
			{
				b[i]=stack[top];
				top++;
				stack[top]=i;
			}
		}
		else
		{
			b[i]=stack[top];
			top++;
			stack[top]=i;
		}
	}
	for(int i=1;i<=n;i++) printf("%d ",b[i]);
	printf("\n");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值