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

SB题。

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

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

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

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

\[f_i\leftarrow f_{i-1}+num_i\\f_i\leftarrow g_{i-1}+4-num_i\\g_i\leftarrow f_{i-1}+num_i+1\\g_i\leftarrow 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; 
}
posted @ 2020-02-07 18:38  空気力学の詩  阅读(152)  评论(0编辑  收藏  举报