[GDKOI2016] Day2 QT与泰剧 数位dp

诶终于到博客第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;
}

你可能感兴趣的:(动态规划,GFOJ,GDKOI)