巧背圆周率

题目描述

想要背诵一段很长的数字,比如圆周率,可以将这些数字分割成一个个片段,根据每个片段的规律做不同的记忆训练。不妨假定每个片段最少 3 个数,最多 6 个数,各种片段记忆难度定义如下:

  • 若所有数字相同,如 66688888 等,则记忆难度为 1;
  • 公差为 11 或者 −1−1 的等差数列,如 345643210 等,记忆难度为 2;
  • 两个数字交替出现,如 31368686 等,记忆难度为 4;
  • 其他等差数列,如 7531369 等,记忆难度为 5,但注意 36912 不算等差数列,因为我们只考虑一位数字;
  • 不属于上述任何一条规律的,比如 2794 等,记忆难度为 10。

现在给定一个由数字构成的字符串 s,请找出一个分割片段的方法,使得所有片段记忆难度之和最小。

输入格式

一个由数字构成的字符串 s。

输出格式

单个整数:表示记忆难度之和的最小值。

数据范围

设 s 的长度为 n,则

#对 30% 的数据 3≤n≤2e1;

#对 60% 的数据 3≤n≤1e4;

#对 100% 的数据 3≤n≤1e5。

样例数据

输入:
314159265358979323846
输出:
34
说明:
分成(314159)(265358)(979)(323846),总难度为10+10+4+10=34
输入:
271828182845904523536
输出:
40
说明:
分成(271828)(182845)(904523)(536),总难度为40
输入:
12122222
输出:
5
说明:
分成(1212)(2222),总难度4+1=5

思路:

是一道区间dp问题。设dp[i]为前i个数的记忆难度(3=<i<=n),明显其记忆难度可以由
dp[i-k]+dif(i,k)得到(3=<k<=6,i>=k),dif(i,k)为第i个数字为开始往前k长度这个区间范围的记忆难度。枚举k=3~6, 取最小的即可。即状态转移方
程为:dp[i]=min(dp[i],dp[i-k]+dif(i,k))
最后答案就是dp[n]

/*分析:
  是一道区间dp问题。设dp[i]为前i个数的记忆难度(3=<i<=n),明显其
  难度可以由dp[i-k]+dif(i,k)得到(3=<k<=6),dif为第i个数字为开始往前
  k长度这个区间范围的记忆难。枚举k=3~6, 取最小的即可。即状态转移方
  程为:dp[i]=min(dp[i],dp[i-k]+dif(i,k)
  最后答案就是dp[n]
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
const long long INF=1e18;
long long dp[maxn];
string str;
long long dif(int end,int l){
	long long val[5]={1,2,4,5,10};
	end--;
	int gc=str[end]-str[end-1];
	int cnt=0;
	for(int i=end-1;i>=(end-l+1);i--){
  		if(str[i]!=str[i+1]){//全数字相等待情况
			val[0]=0;
		}if((str[i+1]-str[i])!=gc){//等差数列
			val[1]=0;val[3]=0;
		}else{
			if(abs(gc)==1){val[3]=0;}
            else{val[1]=0;}
		}cnt++;
		if(cnt>1&&str[i]!=str[i+2]){//两个交替数字
			val[2]=0;
		}
	}for(int i=0;i<5;i++){
		if(val[i])return val[i];
	}
}int main(int argc, char** argv) {
	cin>>str;
	int len=str.length();
	for(int i=1;i<=len;i++){
		dp[i]=INF;
		for(int j=3;j<=6&&(i-j)>=0;j++){
			dp[i]=min(dp[i],dp[i-j]+dif(i,j));
		}
	}cout<<dp[len];return 0;
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值