dp处理大数整除6的最大位数Divide by Six

                                                    题址:https://oj.ejq.me/problem/24   

  Divide by Six

 
 
Input file: standard input
Output file: standard output
Time limit: 1 second
Memory 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
题意:一个小于等于100000位的数字n,(10^100000>=n>=1);在这个数字中选出一些数字(不可改变顺序)组成6的倍数,输出符合条件的最长的位数。

例如样例0010456,选1056符合条件。如果找不到符合条件的则输出-1s;

(下面出现的余数都表示取余6的余数)

思路:首先int dp[100010][6];dp【i】【j】表示前i位(余数为j)的最长的位数;

dp初始化为-1e9;用ans来存最大值,ans初始化也为-1e9。如果数字中有0的话,ans至少是1;

dp【i】【0】一定表示前i位能整除6的最大位数。

因为dp【i】【j】可以由dp【i-1】【k】+1得来。

下面的t表示第i位上的数字。

状态转移方程:dp[i][(j*10+t)%6]=max(dp[i][(j*10+t)%6],dp[i-1][j]+1);  

附上AC代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#define LL long long int
#define inf 0x3f3f3f3f
#define N 1000010
using namespace std;
char a[100005];
int dp[100005][7];
int main()
{
    while(~scanf("%s",a+1))
    {
        int n=strlen(a+1);
        for(int i=0;i<=n;i++)
            for(int j=0;j<6;j++)
                dp[i][j]=-inf;
            int ans=-inf;
            for(int i=1;i<=n;i++)
                if(a[i]=='0')
            {
                   ans=1;
                break;
            }
           for(int i=1;i<=n;i++)
           {
               int t=a[i]-'0';
               if(t!=0)
                dp[i][t%6]=max(dp[i][t%6],1);
               for(int j=0;j<6;j++)
               dp[i][j]=max(dp[i-1][j],dp[i][j]);
               for(int j=0;j<6;j++)
               {
                   dp[i][(j*10+t)%6]=max(dp[i][(j*10+t)%6],dp[i-1][j]+1);
               }
               ans=max(ans,dp[i][0]);
           }
           if(ans>0)
            printf("%d\n",ans);
           else
            printf("-1s\n");

    }
}
比赛后看第一名的代码,才知道原来这题能用dp做。这真是一道好题啊啊啊。
杭电的一道类似题:http://acm.hdu.edu.cn/showproblem.php?pid=6020  都是好题。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值