woj-Divide by Six (dp)(方法巧妙)

来源:互联网 发布:软件版权相关解释 编辑:程序博客网 时间:2024/05/20 14:24

请以此题面为准

无解时输出-1s而不是WTF

数据可能有前导零

Input file: standard inputOutput file: standard output Time limit: 1 secondMemory limit: 512 mebibytes

A positive integer number n is written on a blackboard. It consists of not more than 10^5105 digits. You have to transform it into a mogicalnumber by erasing some of the digits, and you want to erase as few digits as possible.

The number is lucky if it consists of at least one digit, doesn't have leading zeroes and is a multiple of 6. For example, 0, 66,66666 are lucky numbers, and 00, 25, 77 are not.

Write a program which for the given nn will find a mogical number such that nn can be transformed into this number by erasing as few digits as possible. You can erase an arbitraty set of digits. For example, they don't have to go one after another in the number nn.

Print the length of your answer after the erasing.

If it's impossible to obtain a lucky number, print -1s.

Input

The first line of input contains nn -- a positive integer ( 1\le n \le 10^{100000}1n10100000 ).

Output

Print one number — the number of your lucky number obtained by erasing as few as possible digits. If there is no answer, print -1s.

Example

Input 1

0010456

Output 1

4

Input 2

11

Output 2

-1s

这道题可以手动模拟,但是我不会,我学习了大神的dp做法

代码很短,只要想明白了也不是很难

先贴代码再进行分析

#include<stdio.h>#include<iostream>#include<cmath>#include<string.h>using namespace std;const int INF=1e9;char s[100000+10];int dp[100000+10][7];int main(){    scanf("%s",s+1);    int len=strlen(s+1);    for(int i=0; i<=len; i++)//开一个dp数组,初始化        for(int j=0; j<6; j++)            dp[i][j]=-INF;    int ans=-INF;    for(int i=1; i<=len; i++) if(s[i]=='0')ans=1;//如果数字;里有0,那么输出结果至少为1    for(int i=1; i<=len; i++)    {        int t=s[i]-'0';//字符串转化为数字        if(t!=0)            dp[i][t%6]=1;  //将t余上6表示t余上后的剩余值        for(int j=0; j<=5; j++)   //如果不取,那么就直接把前面的搬过来            dp[i][j]=max(dp[i-1][j],dp[i][j]);        for(int j=0; j<=5; j++)     //如果取,那么就在上一次的基础上+1            dp[i][(j*10+t)%6]=max(dp[i-1][j]+1,dp[i][(j*10+t)%6]);//(j*10+t)表示加上前面没余完的数看看能不能余完        ans=max(ans,dp[i][0]);    }    if(ans>0)        printf("%d\n",ans);    else        printf("-1s\n");}

次动规的核心就是分段取余(方法非常巧妙)

对于一个数我先对它取余,当我后面又加上一位的时候,我用这个数余后的数乘上10再加上后一位数,然后再取余

如果取余为0了,那么这两位数为6的倍数

如96   先用9对6取余,剩下3.,下一次的话3*10+6再次对6取余

为0,说明96是6的倍数

这就是   j*10+t  的含义。   

dp【i】【j】里面存的就是长度,是模后剩下j的可选数字的长度    

对于每一位,我先把上一次模剩下的存过来,这是第一次dp的意义

第二次dp的意义是我新加入的这个数t如果能使我存下的dp的长度变长,那么就+1

其中dp【i】【0】表示到第i个数字的最大的长度

如果还是不理解那么就手动模拟一下过程

推荐模拟数   242

模拟出过程就会更好理解了






0 0
原创粉丝点击