UVA580 Critical Mass 【思维+DP】

13 篇文章 0 订阅
3 篇文章 0 订阅

为表示方便,设字符U为0,设字符L为1,题目转化为求长度为n的非法01串种类数(含连续三位000即为非法)

反向思维,可用DP维护长度为 i i i的串的合法状态数,不难发现初始化为:

d p [ 1 ] = 2 dp[1] = 2 dp[1]=2

  • (0, 1)

d p [ 2 ] = 4 dp[2] = 4 dp[2]=4

  • (00, 01, 10, 11)

d p [ 3 ] = 7 dp[3] = 7 dp[3]=7

  • (001, 010, 011, 100, 101, 110, 111)

转移方程为:

d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] + d p [ i − 3 ] dp[i] = dp[i-1] + dp[i-2] + dp[i-3] dp[i]=dp[i1]+dp[i2]+dp[i3]

三个子项分别对应尾部追加 “ 1 ” , “ 10 ” , “ 100 ” “1”, “10”, “100” “1”,“10”,“100”子串的情况,转移结果示例:

d p [ 4 ] = 13 dp[4] = 13 dp[4]=13

  • 来自 d p [ 1 ] dp[1] dp[1]的转移 (0100, 1100) 共2种
  • 来自 d p [ 2 ] dp[2] dp[2]的转移 (0010, 0110, 1010, 1110) 共4种
  • 来自 d p [ 3 ] dp[3] dp[3]的转移 (0011, 0101, 0111, 1001, 1011, 1101, 1111) 共7种

易自证编码互不冲突。

至此,问题可以通过全排列数减对应合法状态数得到非法状态数进行求解:

a n s [ n ] = 2 n − d p [ n ] ans[n] = 2^n - dp[n] ans[n]=2ndp[n]

代码如下:

#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 30 + 10;
int dp[maxn];   // number of valid 0-1 strings (substring 000 is illegal)
int main()
{
    int n;
    dp[1] = 2;  // 0, 1
    dp[2] = 4;  // 00, 01, 10, 11
    dp[3] = 7;  // 001, 010, 011, 100, 101, 110, 111
    
    for (int i = 4; i < maxn; i ++){
        dp[i] += dp[i-1];   // += 1
        dp[i] += dp[i-2];   // += 10
        dp[i] += dp[i-3];   // += 100
    }
    while (cin >> n && n){
        cout << (int)ceil(pow(2,n)) - dp[n] << endl;;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sycamore_Ma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值