把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【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;//输出方案数
}
posted @ 2020-05-12 16:33  TheLostWeak  阅读(170)  评论(0编辑  收藏  举报