2015 Multi-University Training Contest 5(HDOJ5351)

本文针对HDOJ5351题提供了解题思路与Java代码实现。通过对fib字符串的构造规律进行分析,采用大数处理方法解决字符串长度超出常规范围的问题,并通过数组记录与拆分优化计算过程。

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

官方题解:http://blog.sina.com.cn/duoxiao2015


感觉整理太水的题完全没用,从这次之后就不整理水题了,水题定义:比赛时超过300人AC的题目

HDOJ5344、5347、5349均为600+人做出来的水题,解法见官方题解


HDOJ5351

题意:定义一个fib字符串

fib[1]=b

fib[2]=a

fib[i]=fib[i-1]fib[i-2],i>2

fib[n]的前m个字符构成的字符串s,求s的前后缀相等的串最长的长度,s的前后缀不等于s

思路:m的规模明显超过2^64,所以这题要用到大数,我就直接上java写

观测发现,s可以拆成若干个fib[x]之和,把x记录在a数组里,且有a[i]-a[i-1]>=2恒成立

分情况讨论:

情况1:a数组只有一个数,fib[a[0]]=fib[a[0]-2]fib[a[0]-3]fib[a[0]-2],结果就是fib[a[i]-2]

情况2:a数组不止一个数,且把fib[a[0]]拆分成fib[a[0]-1]fib[a[0]-2],并把相同的fib[x]靠后的那个fib[a[i]]拆分成fib[a[i]-1]fib[a[i]-2]

拆分结束,a数组最末尾的值大于1则说明除fib[a[0]-1]外,后面其余的字符构成的后缀,就是结果的长度

拆分束,a数组最末尾的值不大于1则说明除fib[a[0]]外,后面其余的字符构成的后缀,就是结果的长度

PS:官方题解的思路会比我的思路好

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
	static int T,n;
	static BigInteger fib[]=new BigInteger[1010];
	static BigInteger m,sum;
	static BigInteger mod = new BigInteger("258280327");
	static int a[]=new int[1010];
	
	public static void main(String[] args) {
		Scanner cin=new Scanner(System.in);
		T=cin.nextInt();
		fib[1]=BigInteger.ONE;
		fib[2]=BigInteger.ONE;
		for(int i=3;i<1010;i++){
			fib[i]=fib[i-1].add(fib[i-2]);
		}
		while(T--!=0){
			n=cin.nextInt();
			m=cin.nextBigInteger();
			
			sum=BigInteger.ZERO;
			int p=0;
			int k=n;
			a[p]=k;
			while(!m.equals(sum.add(fib[a[p]]))){
				a[p]--;
				a[p+1]=a[p]-1;
				if(m.compareTo(sum.add(fib[a[p]]))==1){
					sum=sum.add(fib[a[p]]);
					p++;
				}
			}
			//System.out.println("p"+" "+p);
			//System.out.println("a:"+" "+a[0]+" "+a[1]+" "+a[2]+" "+a[3]+" "+a[4]+" ");		
			if(p>0){
				sum=m;
				boolean flag=false;
				for(int i=0;i<p;i++){
					if(i!=p&&a[i]-a[i+1]>2){
						flag=true;
						break;
					}
					if(i==p){
						if(a[p]>=4)flag=true;
					}
				}
				if(flag)sum=sum.subtract(fib[a[0]-1]);
				else sum=sum.subtract(fib[a[0]]);
			}
			if(p==0){
				if(a[p]>3)sum=fib[a[p]-2];
				else sum=BigInteger.ZERO;
			}
			System.out.println(sum.mod(mod));
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值