【JZOJ4213】对你的爱深不见底

本文介绍了一种基于神奇字符串规则的权值计算方法,通过斐波那契数列的高精度计算,解决小R给小Y明信片上的数学难题。文章详细解析了算法思路,包括打表找规律和高精度暴力计算过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

description

出乎意料的是,幸运E 的小R 居然赢了那个游戏。现在欣喜万分的小R 想要写一张明信片给小Y,但是因为小R 非常羞涩,所以他打算采用一些比较神奇的方式来表达。
他定义了一些字符串,s1 = a,s2 = b,si =s_i-1 + s_i-2 (i >=3)。同时他定义了一个字符串s 的权值为一个最大的i <|s|满足s 长度为i 的前缀等于长度为i 的后缀。比如字符串aba 的权值就是1,abab 的权值就是2,aaaa 的权值就是3。
现在小R 在明信片上给出了两个数n 和m,他想要告诉小Y 的信息是字符串sn 的前m个字符组成的字符串的权值。你可以帮小Y 计算一下吗?


analysis

  • 打表找规律

  • 需要结合打表和出题人九条可怜的温馨提示

  • nnn最小,且∣s[n]∣&gt;m+1|s[n]|&gt;m+1s[n]>m+1时,答案即为m−∣s[n−2]∣m-|s[n-2]|ms[n2]

  • 那么直接高精度暴力斐波那契数列,暴力判断就好

  • 有很多坑点,比如高精度下+1+1+1什么的,调的我爆肝


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 1005
#define MAXLEN 305
#define mod 258280327
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))

using namespace std;

char s[MAXLEN];
ll n,m,T,ans;

O3 inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
struct BIGNUM
{
	ll num[MAXLEN],len;
	BIGNUM()
	{
		memset(num,0,sizeof(num)),len=1;
	}
	BIGNUM operator=(const char s[])
	{
		len=strlen(s);
		fo(i,0,len-1)num[i]=s[len-i-1]-'0';
		while (num[len-1]==0 && len>1)--len;
		return *this;
	}
	BIGNUM operator=(const ll x)
	{
		ll temp=x;
		len=1;
		do
		{
			num[len-1]=temp%10;
			temp/=10,len++;
		}while (temp);
		while (num[len-1]==0 && len>1)--len;
		return *this;
	}
	BIGNUM operator+(const BIGNUM &x)const
	{
		BIGNUM temp;
		temp.len=max(len,x.len)+1;
		fo(i,0,temp.len-1)
		{
			temp.num[i]+=num[i]+x.num[i];
			temp.num[i+1]=temp.num[i]/10;
			temp.num[i]%=10;
		}
		while (temp.num[temp.len-1]==0 && temp.len>1)--temp.len;
		return temp;
	}
	BIGNUM operator-(const BIGNUM &x)const
	{
		BIGNUM temp;
		temp.len=max(len,x.len);
		fo(i,0,temp.len-1)
		{
			temp.num[i]+=num[i]-x.num[i];
			if (temp.num[i]<0)temp.num[i]+=10,--temp.num[i+1];
		}
		while (temp.num[temp.len-1]==0 && temp.len>1)--temp.len;
		return temp;
	}
	BIGNUM operator*(const BIGNUM &x)const
	{
		BIGNUM temp;
		temp.len=len+x.len;
		fo(i,0,len-1)
		{
			fo(j,0,x.len-1)
			{
				temp.num[i+j]+=num[i]*x.num[j];
				temp.num[i+j+1]+=temp.num[i+j]/10;
				temp.num[i+j]%=10;
			}
		}
		while (temp.num[temp.len-1]==0 && temp.len>1)--temp.len;
		return temp;
	}
	bool operator<(const BIGNUM &x)const
	{
		if (len>x.len)return 0;
		if (len<x.len)return 1;
		fd(i,len-1,0)if (num[i]!=x.num[i])return num[i]<x.num[i];
		return 0;
	}
	void print()
	{
		fd(i,len-1,0)printf("%lld",num[i]);
		printf("\n");
	}
}f[MAXN],temp,tempp,one;
O3 int main()
{
	//freopen("T3.in","r",stdin);
	T=read();
	f[1]=f[2]=one=1;
	fo(i,3,MAXN-2)f[i]=f[i-1]+f[i-2];
	while (T--)
	{
		n=read(),scanf("%s",&s),temp=tempp=s;
		tempp.num[0]++,tempp.num[tempp.len]=0;
		fo(i,0,tempp.len-1)if (tempp.num[i]>9)tempp.num[i+1]++,tempp.num[i]-=10;else break;
		if (tempp.num[tempp.len])tempp.num[++tempp.len]=1;
		fo(i,1,MAXN+2)
		{
			if (tempp<f[i])
			{
				temp=temp-f[i-2];
				ans=0;
				fd(i,temp.len-1,0)
				{
					ans=ans*10+temp.num[i];
					ans%=mod;
				}
				printf("%lld\n",ans%mod);
				break;
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值