oj 1289
提示:递推,同余
询问是否为3的倍数,也就说,这个数模上3后的结果为0
实际上,我们可以根据模后的结果划分为若干的等价类,也就是同余系的概念。
对于一个数 234342343423434 模3的结果就是:(2343 % 3 * 10 + 4) % 3。这是简单的同余概念
回到本题,我们考虑 f[i][j]
表示处理完了前 i
位后,模后的结果为 j
的个数。(由同余系的概念,我们可以知道,只关注模后的结果即可)。那么我们在考虑到第 i+1
位的时候,无非就只有两种情况:第 i+1i+1i+1 位删除/保留。根据相应的情况转移即可。
需要注意的是,由于不能有前导0和正数的限制 ,我们需要在转移时,作出当前位为第一位的递推附加。
#include <stdio.h>
#include <string.h>
char s[5007];
#define MOD 1000000007
int f[5004][3];
void sol()
{
int n = strlen(s + 1);
for (int i = 0; i <= n + 2; ++i)
f[i][0] = f[i][1] = f[i][2] = 0;
for (int i = 1; i <= n; ++i)
{
int t = s[i] - '0';
f[i][0] = f[i - 1][0];
f[i][1] = f[i - 1][1];
f[i][2] = f[i - 1][2];
f[i][(0 * 10 + t) % 3] += f[i - 1][0]; f[i][(0 * 10 + t) % 3] %= MOD;
f[i][(1 * 10 + t) % 3] += f[i - 1][1]; f[i][(1 * 10 + t) % 3] %= MOD;
f[i][(2 * 10 + t) % 3] += f[i - 1][2]; f[i][(2 * 10 + t) % 3] %= MOD;
if (t != 0) // 单独为1位数
f[i][t % 3] ++, f[i][t % 3] %= MOD;
}
printf("%d\n", f[n][0]);
}
int main() {
while (scanf("%s", s + 1) == 1)
{
sol();
}
return 0;
}