BZOJ 1111 POI2007 四进制的天平

3 篇文章 0 订阅

兹磁伙伴们刷POI

提示:
1. 把这玩意用四进制表示看看
2. 模拟一下退位的过程 , 一次退几位比较合理呢?

详细题解在代码后:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <algorithm>

using namespace std;
const int maxn = 2100;
const int INF = 0x3f3f3f3f;

int n;
char s[maxn] , s1[maxn];
deque<int> a;

__inline int dig(char c) { return c-'0'; }
bool div()
{
    if(n==0) return false;
    int last = 0 , nn = 0 , st = 0;
    if(dig(s[0])<4) last = dig(s[0]) , st = 1;

    for(int i=st;i<n;i++) 
    {
        int sum = dig(s[i]);
        sum+= 10*last;
        last = sum%4;
        s1[nn++] = sum/4+'0';
    }
    a.push_front(last);

    n = nn;
    memcpy(s, s1, sizeof(s1));
    return true;
}

const int modu = 1e9;
int d[maxn][2];
int w[maxn][2];

int main(int argc, char *argv[]) {

    scanf("%s" , s);

    n = strlen(s);

    while(div());
    a.push_front(0); a.push_back(0);

    d[0][0] = 0; w[0][0] = 1;
    d[0][1] = INF;

    for(int i=1;i<a.size();i++) for(int j=0;j<2;j++)
    {
        d[i][j] = min(d[i-1][0]+j*5 , d[i-1][1]+j*3);
        if(d[i][j]==d[i-1][0]+j*5) w[i][j] += w[i-1][0];
        if(d[i][j]==d[i-1][1]+j*3) w[i][j] += w[i-1][1];
        d[i][j] += a[i]*(!j?1:-1);
        w[i][j] %= modu;
    }

    printf("%d\n" , w[a.size()-1][0]);
    return 0;
}

有几个显而易见的结论:

  • 最高位不能高于这个数四进制表示的位数+1
  • 如果要退位 , 每次最多退一位 , 也就是把高位上的1 , 拆成4个低位
  • 每个位上的数最多只有两种状态 , 这取决于上一位是否退了

d[i][j]ii1(j==0)(j==1)退
w[i][j]

然后就可以开心的DP了 , 转移方程很好写啦……代码浓缩过 , 所以最好自己写写转移方程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值