【模拟】Vijos P1005 超长数字串

64 篇文章 3 订阅
44 篇文章 0 订阅

题目链接:

  https://vijos.org/p/1005

题目大意:

  无限的正整数按顺序拼接成字符串S(S=12345678910111213...),给你一个字符串A(len<=200)求这个字符串在S中最早出现的位置。

  (答案超过long long ,无法用KMP,不要相信标签)

题目思路:

  【模拟】

  这题简直了!!!!!!大模拟啊。细节超级多。疯狂TLE+WA+RE了17次才AC。

  第一次写了一整天没写过,放了好久,昨天又写了一整天(哎效率低下。)

  首先分两种普遍的情况和两种特殊情况考虑。

  普遍情况一是S串是由三段组成,头,尾和中间数字串,头尾可能不完全。这时候枚举中间数字串的长度和起始位置,就可以判断出最早出现的数字

  (如:123[98 12399 124]00  99[8 999 1000 10]01 等)

  (一开始我是想把这个再分情况考虑,发现有进位什么的太麻烦了后来直接把这个数压到高精度中,先-1判断和头是否匹配,再每次+1判断和后面的字符串匹不匹配,尾部同理)

  普遍情况二是S串是由两段组成,前面的数字的尾部和后面的数字的头部组成,这时要枚举重叠部分的长度和断开的位置。

  (如:1[2 1]3  123[699 1237]00    60211602应该是 1[6021 1602]2 而不是[60211 602]12)

  (一开始我忘记了这种情况WA了好久。。感觉自己好蠢。)

  特殊情况一是全为0的情况,这是都不符合上面的情况,就需要在头部再添上一个1,肯定是最早出现的。

  特殊情况二是全为9的情况,除了单个9是9以外,两位数以上的9都可以拆成 8[9999... 9]0000... 这个答案明显比[9999...] 10000...优。

  (不知道自己还有没有漏情况,希望没有吧,望指教。)




//
//by coolxxx
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<iomanip>
#include<map>
#include<memory.h>
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//#include<stdbool.h>
#include<math.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a) ((a)>0?(a):(-(a)))
#define lowbit(a) (a&(-a))
#define sqr(a) ((a)*(a))
#define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
#define mem(a,b) memset(a,b,sizeof(a))
#define eps (1e-8)
#define J 10
#define mod 1000000007
#define MAX 0x7f7f7f7f
#define PI 3.14159265358979323
#define N 404
using namespace std;
typedef long long LL;
int cas,cass;
int n,m,lll,ans;
double anss;
char s[N];
int a[N],b[N],t[N],c[N];
void gjdchange(int a[],int l,int r)//l~r中间的字符转化为高精度数a
{
	int i;
	mem(t,0);
	t[0]=r-l+1;
	for(i=1;i<=r-l+1;i++)
		t[i]=s[r-i+1]-'0';
	memcpy(a,t,sizeof(t));
}
void plu(int a[])//高精度a+1
{
	int i;
	for(i=1,a[1]++;a[i]>=J;i++)
		a[i]-=J,a[i+1]++;
	a[0]=max(a[0],i);
}
void dec(int a[])//高精度a-1
{
	int i;
	for(i=1,a[1]--;a[i]<0;i++)
		a[i]+=J,a[i+1]--;
	while(!a[a[0]] && a[0]>1)a[0]--;
}
int gjdbigger(int a[],int b[])//高精度a和高精度b比大小  1:a>b  0:a<b  -1:a=b
{
	if(a[0]!=b[0])return a[0]>b[0];
	int i;
	for(i=a[0];i;i--)if(a[i]!=b[i])return a[i]>b[i];
	return -1;
}
bool tou(int i,int len)//判断头部是否满足
{
	int ii;
	dec(a);
	for(ii=1;ii<=a[0] && i-ii;ii++)
		if(a[ii]!=s[i-ii]-'0')return 0;
	return 1;
}
void gjdjia(int a[],int b[],int c[])//高精度a+高精度b,答案存在高精度c里
{
	int i;
	mem(t,0);
	t[0]=max(a[0],b[0]);
	for(i=1;i<=t[0];i++)
		t[i]=a[i]+b[i];
	for(i=1;i<=t[0];i++)
		t[i+1]+=t[i]/J,t[i]%=J;
	while(t[t[0]+1])t[0]++;
	while(!t[t[0]] && t[0]>1)t[0]--;
	memcpy(c,t,sizeof(t));
}
void gjdjian(int a[],int b[],int c[])//高精度a-高精度b,答案存在高精度c里
{
	int i;
	mem(t,0);
	t[0]=a[0];
	for(i=1;i<=t[0];i++)
		t[i]=a[i]-b[i];
	for(i=1;i<=t[0];i++)
		if(t[i]<0)t[i+1]--,t[i]+=J;
	for(i=1;i<=t[0];i++)
		t[i+1]+=t[i]/J,t[i]%=J;
	while(t[t[0]+1])t[0]++;
	while(!t[t[0]] && t[0]>1)t[0]--;
	memcpy(c,t,sizeof(t));
}
void gjdchengdjd(int a[],int b,int c[])//高精度a*单精度b,答案存在高精度c里
{
	int i;
	mem(t,0);
	t[0]=a[0]+3;
	for(i=1;i<=a[0];i++)
		t[i]=a[i]*b;
	for(i=1;i<=t[0];i++)
		t[i+1]+=t[i]/J,t[i]%=J;
	while(t[t[0]+1])t[0]++;
	while(!t[t[0]] && t[0]>1)t[0]--;
	memcpy(c,t,sizeof(t));
}
void cal(int len,int head)//已知a为第一个完整出现的数字,len为长度,head为出现的位置
{
	int i,j;
	int tmp[N];
	mem(tmp,0);
	//gjdchange(a,head,head+len-1);
	b[0]=1;b[1]=9;c[0]=1;c[1]=0;
	for(i=1;i<a[0];i++)
	{
		gjdchengdjd(b,i,tmp);
		gjdjia(c,tmp,c);
		b[b[0]+1]=9;b[b[0]++]=0;
	}
	b[b[0]]=0;
	b[0]=a[0];b[b[0]]=1;
	for(i=1;i<a[0];i++)b[i]=0;
	gjdjian(a,b,a);
	gjdchengdjd(a,len,b);
	gjdjia(c,b,c);
	mem(b,0);
	b[0]=1;b[1]=head-2;
	while(b[b[0]]>=J)b[b[0]+1]=b[b[0]]/J,b[b[0]++]%=J;
	gjdjian(c,b,c);
}
void work(int &len,int &head)//从中间断开分成两个数字的情况
{
	int i,j,l;
	if(len<=n)
		gjdchange(a,head,head+len-1);
	else a[0]=MAX;
	b[0]=0;
	for(l=0;l<=(n+1)/2+1;l++)//最终长度n-l
	{
		for(j=1;j<=l;j++)
			if(s[j]!=s[n-l+j])break;
		if(j<=l)continue;
		for(i=l+2;i<=n-l;i++)
		{
			b[0]=0;
			for(j=i-1;j;j--)b[++b[0]]=s[j]-'0';
			for(j=n-l;j>=i;j--)b[++b[0]]=s[j]-'0';
			plu(b);
			if(b[b[0]]==0)continue;
			for(j=0;j<b[0] && i+j<=n;j++)
				if(b[b[0]-j]!=s[i+j]-'0')break;
			if(j<b[0] && i+j<=n)continue;
			if(gjdbigger(a,b)){memcpy(a,b,sizeof(b));len=n-l;head=i;}
		}
	}
}
bool all9()//长度大于2且全是9的特殊情况 拆成8999999999...+9000000000...
{
	int i;
	gjdchange(b,1,n);
	for(i=1;i<=b[0];i++)if(b[i]!=9)return 0;
	if(b[0]==1)return 0;
	b[b[0]]=8;plu(b);
	memcpy(a,b,sizeof(b));
	return 1;
}
bool all0()//全是0的特殊情况 1+00000000...
{
	int i;
	gjdchange(b,1,n);
	for(i=1;i<=b[0];i++)if(b[i]!=0)return 0;
	b[++b[0]]=1;
	memcpy(a,b,sizeof(b));
	return 1;
}
void gjdprint(int a[])//输出高精度a
{
	int i;
	printf("%d",a[a[0]]);
	for(i=a[0]-1;i;i--)
		printf("%d",a[i]);
	puts("");
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("1.txt","r",stdin);
//	freopen("2.txt","w",stdout);
	#endif
	int i,j,k,l;
//	for(scanf("%d",&cas);cas;cas--)
//	for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
	while(~scanf("%s",s+1))
//	while(~scanf("%d",&n))
	{
		s[0]='.';
		n=strlen(s)-1;
		for(l=1;l<=n;l++)
		{
			for(i=1;i<=l && i+l-1<=n;i++)
			{
				gjdchange(a,i,i+l-1);
				if(a[a[0]]==0)continue;//前导0不符合要求
				if(i!=1)
				{
					if(!tou(i,l))continue;
					plu(a);
				}
				for(j=i+l;j<=n;j+=a[0])
				{
					plu(a);
					for(k=0;j+k<=n && k<a[0];k++)
					{
						if(a[a[0]-k]!=s[j+k]-'0')break;
					}
					if(j+k>n || k<a[0])break;
				}
				if(j+k>n)break;
				if(j>n)break;
			}
			if(i<=l && i+l-1<=n)break;
		}
		//以上是将字符串拆成三段枚举,头,尾和中间的数字
		work(l,i);
		if(all9())cal(n,n);
		else if(all0())cal(n+1,0);
		else cal(l,i);
		gjdprint(c);
	}
	return 0;
}
/*
//

//
*/


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值