BZOJ 1111: [POI2007]四进制的天平Wag

SB题。

很容易想到先二话不说把十进制转四进制,然后我们考虑DP:

(f_{i})表示从高位到低位的第(i)位填成目标状态的最小步数/方案数

(g_{i})表示从高位到低位的第(i)位填成目标状态(+1)的最小步数/方案数(因为涉及到向下一位退位)

那么我们容易得到以下转移:

[f_ileftarrow f_{i-1}+num_i\f_ileftarrow g_{i-1}+4-num_i\g_ileftarrow f_{i-1}+num_i+1\g_ileftarrow g_{i-1}+3-num_i\ ]

然后就做完了233

#include<cstdio>
#include<cstring>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=3005,mod=1e9;
struct data
{
    int x,y;
    inline data(CI X=1e9,CI Y=0) { x=X; y=Y; }
    friend inline data operator + (const data& A,CI x)
    {
        return data(A.x+x,A.y);
    }
}f[N],g[N]; int n,len,a[N],b[N]; char s[N];
inline void upt(data& A,const data& B)
{
    if (A.x==B.x) A.y=(A.y+B.y)%mod; else if (B.x<A.x) A=B;
}
int main()
{
    RI i,j; for (scanf("%s",s+1),n=strlen(s+1),i=1;i<=n;++i)
    a[i]=s[n-i+1]-'0'; while (n)
    {
        int ret=0; for (i=n;i;--i) ret=(ret*10+a[i])%4; b[++len]=ret;
        for (i=n;i;--i) a[i-1]+=a[i]%4*10,a[i]/=4; while (!a[n]) --n;
    }
    for (reverse(b+1,b+len+1),f[0]=data(0,1),g[0]=data(1,1),i=1;i<=len;++i)
    upt(f[i],f[i-1]+b[i]),upt(f[i],g[i-1]+(4-b[i])),
    upt(g[i],f[i-1]+(b[i]+1)),upt(g[i],g[i-1]+(3-b[i]));
    return printf("%d",f[len].y),0; 
}
原文地址:https://www.cnblogs.com/cjjsb/p/12274075.html