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;
}
辣鸡老年选手AFO在即