诶终于到博客第100篇了,值得纪念啊
数位dp有很多种写法,大部分是记忆化搜索或者多一维表示是否受限制,我之前的写法一直是一遍普通dp+一遍普通搜索,虽然很好理解但是写起来很挫,这次尝试了一下多一维的做法(实际上我开了两个数组)
F[i][p1][p2] 表示第 i 位(以个位为第一位),p1表示是否全部为质数,p2表示模3的余数。
特别注意处理前导零(我真是菜鸟在这里处理了好久,最后写法也很挫)
#include
#include
#include
#define N 1000050
#define mod 10007
using namespace std;
const bool p[] = {0,0,1,1,0,1,0,1,0,0};
int g,ans,F[N][2][3],G[N][2][3];
char s[N],t[N];
inline void inc(int &x,int y) { x = ( x + y + mod ) % mod; }
int thr() {
int g = 0; int n = strlen(s+1);
for (int i=1;i<=n;i++) g = (g + s[i] - '0') % 3;
return g;
}
bool spj() {
bool flag = 0; int n = strlen(s+1);
for (int i=1;i<=n;i++) if (!p[ s[i]-'0' ]) flag = 1;
return flag;
}
int dp() {
// F[N] [0/1] [0/1/2]
// 被动递推
int r = 0 , n = strlen(s+1);
if (s[1] == '0') return 0;
memset(F,0,sizeof(F));
memset(G,0,sizeof(G));
F[n+1][1][0] = 1;
for (int i=n;i>=1;i--) {
for (int k=0;k<=2;k++)
for (int j=0;j<=9;j++){
if (i!=1 && j != 0 && k == g) inc( r , -F[i][0][k] );
inc( F[i][0][k] , F[i+1][0][ (k-j+9)%3 ] );
if (p[j])
inc( F[i][1][k] , F[i+1][1][ (k-j+9)%3 ] );
else
inc( F[i][0][k] , F[i+1][1][ (k-j+9)%3 ] );
if (i!=1 && j != 0 && k == g) inc( r , F[i][0][k] );
}
int dd = i==1;
for (int k=0;k<=2;k++)
for (int j=dd;j'0';j++) {
inc( G[i][0][k] , F[i+1][0][ (k-j+9)%3 ] );
if (p[j])
inc( G[i][1][k] , F[i+1][1][ (k-j+9)%3 ] );
else
inc( G[i][0][k] , F[i+1][1][ (k-j+9)%3 ] );
}
for (int k=0;k<=2;k++) {
int j = s[i] - '0';
inc( G[i][0][k] , G[i+1][0][ (k-j+9)%3 ] );
if (p[j])
inc( G[i][1][k] , G[i+1][1][ (k-j+9)%3 ] );
else
inc( G[i][0][k] , G[i+1][1][ (k-j+9)%3 ] );
}
}
if (spj() && thr() == g) inc(r,1);
inc(r,G[1][0][g]);
// for (int i=2;i<=n;i++) inc(r,F[i][0][g]);
return r;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
scanf("%s",s+1);
scanf("%s",t+1);
g = thr();
inc(ans , dp()); swap(s,t);
inc(ans , -dp()); swap(s,t);
printf("%d\n",ans < 0 ? ans+mod : ans);
return 0;
}
对拍用的暴力(直接交有20分)
#include
#include
using namespace std;
const bool p[] = {0,0,1,1,0,1,0,1,0,0};
int s,t,ans;
bool jud(int x) {
bool flag1 = (x % 3) == (s % 3);
bool flag = 0;
while (x) {
if (!p[x%10]) flag = 1;
x /= 10;
}
return flag && flag1;
}
int main() {
freopen("1.in","r",stdin);
freopen("1.ans","w",stdout);
scanf("%d%d",&s,&t);
for (int i=t+1;i<=s;i++) if (jud(i)) ans++;
printf("%d\n",ans);
fclose(stdin); fclose(stdout);
return 0;
}
造数据(相当简单),可以多造形如x,0这样的数据
#include
#include
#include
#include
using namespace std;
const int maxn = 20000;
int main() {
srand(time(0));
int x = rand() * rand() % maxn + 0 , y = rand() * rand() % maxn + 0;
if (x < y) swap(x,y);
printf("%d %d\n",x,y);
return 0;
}