[POI2007]四进制的天平Wag

Description
Mary准备举办一个聚会,她准备邀请很多的人参加她的聚会。并且她准备给每位来宾准备一些金子作为礼物。为了不伤及每个人的脸面,每个人获得的金子必须相同。Mary将要用一个天平来称量出金子。她有很多的砝码,所有砝码的质量都是4的幂。Mary将金子置于左边并且将砝码置于右盘或者两个盘。她希望每次称量都使用最少的砝码。并且,他希望,每次都用不同的称量方法称出相同质量的金子。对于给定的质量n,Mary希望知道最少需要用多少个砝码可以完成称量,并且想知道用这么多个砝码一共有多少种方式进行称量。

Input
输入文件仅包含一个整数,表示Mary希望给每个人的金子的质量。(1<=n<=10^1000)

Output
输出文件仅包含一个整数,表示一共可能的称量方式对10^9的模。

Sample Input
166

Sample Output
3

HNIT
一共有三种方式称量出166。166=64+64+16+16+4+1+1。166=256-64-16-16+4+1+1。166=256-64-16-4-4-1-1。


首先把n转成4进制,然后开始从低位向高位DP。
f[i]表示不向下一位借位,g[i]表示向下一位借位,f[i],g[i]都要带上两个参数,为当前用了多少个数和匹配种数。转移方程如下:
f[i]=merge(f[i-1]+T[i],g[i-1]+1+T[i]);
g[i]=mergr(f[i-1]+4-T[i],g[i-1]+3-T[i]);
(注:借到的一位不算在当前第i位上,f[i]记录的只是4^i,不论正负)

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x>=10)     print(x/10);
	putchar(x%10+'0');
}
const int p=1e9;
const int N=1e4;
const int digit=4;
const int base=1e4;
char s[N+10];
struct Bignum{
	int v[N+10],len;
	Bignum(){len=1,memset(v,0,sizeof(v));}
	void read(){
		scanf("%s",s);
		int t=strlen(s),tim=1;
		len=(t-1)/digit+1;
		for (int i=0,j=t-1;i<j;i++,j--)	swap(s[i],s[j]);
		for (int i=0;i<t;i++){
			v[i/digit]+=(s[i]-'0')*tim,tim*=10;
			if (tim==base)	tim=1;
		}
	}
	void write(){
		printf("%d",v[len-1]);
		for (int i=len-2;~i;i--)	printf("%0*d",digit,v[i]);
		putchar('\n');
	}
}A,Zero;
int operator %(Bignum x,int y){
	for (int i=x.len;i;i--)	x.v[i-1]+=x.v[i]%y*base;
	return x.v[0]%y;
}
Bignum operator /(Bignum &x,int y){
	for (int i=x.len;~i;i--)	x.v[i-1]+=x.v[i]%y*base,x.v[i]/=y;
	while (!x.v[x.len]&&x.len)	x.len--;
	x.len++;
	return x;
}
bool operator ==(const Bignum &x,const Bignum &y){
	if (x.len!=y.len)	return 0;
	for (int i=0;i<=x.len;i++)	if (x.v[i]!=y.v[i])	return 0;
	return 1;
}
bool operator !=(const Bignum &x,const Bignum &y){return !(x==y);}
struct Dp{
	int x,y;
	Dp(){}
	Dp(int _x,int _y){x=_x,y=_y;}
}f[N+10],g[N+10];
Dp min(const Dp &a,const Dp &b){return a.x<b.x?a:b;}
Dp operator +(const Dp &a,int b){return Dp(a.x+b,a.y);}
Dp operator +(const Dp &a,const Dp &b){return a.x==b.x?Dp(a.x,(a.y+b.y)%p):min(a,b);}
int T[N+10];
int main(){
	int tot=1;
	A.read();
	while (A!=Zero)	T[tot++]=A%4,A=A/4;
	f[0]=Dp(0,1),g[0]=Dp(inf,0);
	for (int i=1;i<=tot;i++){
		f[i]=(f[i-1]+T[i])+(g[i-1]+(T[i]+1));
		g[i]=(f[i-1]+(4-T[i]))+(g[i-1]+(3-T[i]));
	}
	printf("%d\n",f[tot].y);
	return 0;
}
posted @ 2018-04-25 16:03  Wolfycz  阅读(493)  评论(0编辑  收藏  举报