[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]=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]);
(ps:借到的一位不算在当前第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;
}

猜你喜欢

转载自www.cnblogs.com/Wolfycz/p/8945344.html