【BZOJ1111】[POI2007] 四进制的天平Wag(DP)
大致题意: 要把一个高精度大整数表示为若干\(4\)的幂的和与差,使得所用\(4\)的幂数量最少。求方案数。
前言
似乎没什么可说的。。。
大力找规律找半天,最后发现是道\(DP\)题,求心理阴影面积。。。
马上就要吃饭了,也来不及扯啥了,赶紧水完走人。
动态规划
首先,遇上这种题,肯定先把十进制转化为四进制。
考虑我们定义一个结构体\(S\),由\(f,g\)两个变量组成,分别表示数量和方案数。
定义两个\(S\)变量\(A,B\)的加法为:
- 若\(A.f=B.f\),则返回\(S(A.f,A.g+B.g)\)。
- 否则,返回\(f\)较小的那一个。
显然,如果要使某一位满足条件,无非是两种方式:加法或减法。
因此,我们设\(F_x\)和\(G_x\)分别表示从高到低\(DP\)到第\(x\)位,使高于\(x\)位的都满足条件,第\(x\)位满足条件/比目标值大\(1\)(用于退位)的方案数。
则有转移方程:
\[F_x=S(F_{x+1}.f+v_x,F_{x+1}.g)+S(G_{x+1}.f+4-v_x,G_{x+1}.g)
\]
\[G_x=S(F_{x+1}.f+v_x+1,F_{x+1}.g)+S(G_{x+1}.f+3-v_x,G_{x+1}.g)
\]
具体实现详见代码。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define LEN 2000
#define X 1000000000
using namespace std;
int t,v[LEN+5];
struct S
{
int f,g;I S(CI x=0,CI y=0):f(x),g(y){}
I friend S operator + (Con S& A,Con S& B) {return A.f^B.f?(A.f<B.f?A:B):S(A.f,(A.g+B.g)%X);}
}F[LEN+5],G[LEN+5];
struct DecSystem
{
int l,a[LEN+5];
I void read()//读入
{
static string s;cin>>s,l=s.length();for(RI i=1;i<=l;++i) a[i]=s[l-i]&15;
}
I int Mod4()//除以4,返回余数(用于进制转化)
{
RI i,w=0;for(i=l;i;--i) a[i]=10*w+a[i],w=a[i]%4,a[i]/=4;W(l&&!a[l]) --l;return w;
}
}n;
int main()
{
RI i;n.read();W(n.l) v[++t]=n.Mod4();//十进制转四进制
for(F[t+1]=S(0,1),G[t+1]=S(1,1),i=t;i;--i)//动态规划
F[i]=S(F[i+1].f+v[i],F[i+1].g)+S(G[i+1].f+4-v[i],G[i+1].g),//转移F
G[i]=S(F[i+1].f+v[i]+1,F[i+1].g)+S(G[i+1].f+3-v[i],G[i+1].g);//转移G
return printf("%d",F[1].g),0;//输出方案数
}
待到再迷茫时回头望,所有脚印会发出光芒