给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模
被三整除即各位数的和可以被三整除。
显然每选择一个数所造成的结果都会从原来已知的结果加上一些影响而得到,这里可以找几个数发现规律:
1563:当只有1的时候不存在被3整除的情况,只有15的时候存在一种被3整除的情况(15),只有156的时候存在三种被三整除的情况(6,15,156),1563的时候存在7种被3整除的情况(15,63,3,6,156,1563,153).
111,只有111的时候才有一种合法情况。
可以知道,三个取余3得1的数加起来一定是3的倍数,同样一个取余3得2的数和一个取余3得1的数合并一定是3的倍数。
以此类推,所以就有这样的状态转移方程:
- 如果当前位取余3为0:所有组合的模(0,1,2)和此位组合都维持原状,且都可以组成一个同模的数字(1->13取余3仍然是1,但是取余3得1的方案数为原来的两倍),所以各种取余方案数全部乘2,之后取余3为0的方案数单独加一(单独选此位)。
- 如果当前位取余3为1:对于取余3为0的方案来说,总的方案数为原本取余3就是0的方案数(不选这一位)加上取余3为2的方案数(取余3为2加上一个取余3为1的数模3为0)之和。同样,模3=1的方案可以由模3=0(加这一位)的情况加上模3=1(不加这一位)的情况构成,模3=2的方案同理
- 取余3为2的情况如上所述可推得。
import java.util.*;
import java.math.*;
import java.io.*;
import java.text.*;
public class Main5
{
static final int mod=1000000007;
static int status[][]=new int[500][500];
public static void main(String args[])throws IOException
{
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
String tmp=bf.readLine();
int limit=tmp.length();
for(int current=1;current<=limit;current++)
{
int currentValue=Integer.valueOf(tmp.substring(current-1,current));
if(currentValue%3==0)
{
status[current][0]=2*status[current-1][0]+1;
status[current][1]=2*status[current-1][1];
status[current][2]=2*status[current-1][2];
}
else if(currentValue%3==1)
{
status[current][0]=status[current-1][0]+status[current-1][2];
status[current][1]=status[current-1][0]+status[current-1][1]+1;
status[current][2]=status[current-1][2]+status[current-1][1];
}
else
{
status[current][0]=status[current-1][0]+status[current-1][1];
status[current][1]=status[current-1][1]+status[current-1][2];
status[current][2]=status[current-1][2]+status[current-1][0]+1;
}
for(int j=0;j<=2;j++)
status[current][j]%=mod;
}
System.out.println(status[limit][0]);
bf.close();
}
}