UVA580 危险的组合 Critical Mass

  • 题目大意

洛谷传送门

有一些装有铀 U铅 L的盒子,数量均足够多。要求把 n n n ( n ≤ 30 ) (n \le 30) (n30) 个盒子放成一行,但至少有 3 3 3 个装有 U 的盒子放在一起,有多少种放法?

  • 分析

法一

这道题是紫书上很典的一道递推,因为 n ≤ 30 n \le 30 n30 所以并不会爆 int ,我们设 f i f_i fi 为前 i i i 个盒子的总方案数,那么就有:
f 0 = f 1 = f 2 = 0 , f 3 = 1 , f 4 = 3 f_0=f_1=f_2=0,f_3=1,f_4=3 f0=f1=f2=0,f3=1,f4=3
n n n 位的答案即为 f n f_n fn 。好的,前置条件有了,我们来推导一下递推式。这里我们需分类讨论:

  1. 现在已经有 3 3 3 个装有 U 的盒子放在一起,满足条件,那么当前第 i i i 个盒子则有两种选择,分别为放 U 和放 L ,再根据乘法原理得出
    f i = 2 ⋅ f i − 1 f_i=2 \cdot f_{i-1} fi=2fi1

  2. 当前并不满足条件,想要合法,那么前面的盒子里放的元素一定为 LUU ,我们就需要求前面的盒子不合法的方案数,就用全部的方案数减去合法的方案数就是不合法的方案数。我们得出方案数为
    2 i − 4 − f i − 4 2^{i-4} - f_{i-4} 2i4fi4

那么,递推式就为:
f i = 2 ⋅ f i − 1 + 2 i − 4 − f i − 4 f_i=2 \cdot f_{i-1}+2^{i-4} - f_{i-4} fi=2fi1+2i4fi4

我们就可以用递推式与前置条件将从 5 5 5 n n n 的方案数推出来,最后输出即可,时间复杂度为 O ( n ) O(n) O(n)

AC 记录

Code

#include <bits/stdc++.h>
#define int long long
#define AC return 0
#define M(a) memset(a,0,sizeof a)
#define il inline
#define rep(i,l,r) for(int i=l;i<=r;i++)
using namespace std;

const int N=100010;

int f[N];
int n;

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	f[3]=1;
	f[4]=3;
	while(cin>>n && n) {
		rep(i,5,n) f[i]=pow(2,i-4)-f[i-4]+2*f[i-1];
		cout<<f[n]<<endl;
	}
	AC;
}

法二

这次我们用 f i f_i fi 来表示前 i i i 个盒子的不合法总数。

我们知道总方案数为 2 n 2^n 2n ,那么答案就为
2 n − f n 2^n - f_n 2nfn
我们来讨论一下不合法方案数:

  1. 如果第 1 1 1 位是 L ,那么有 f n − 1 f_{n-1} fn1 种方案,不然第 1 1 1 位就应该是 U ;
  2. 如果第 2 2 2 位是 L ,那么有 f n − 2 f_{n-2} fn2 种方案,不然第 2 2 2 位就应该是 U ;
  3. 如果第 3 3 3 位是 L ,那么有 f n − 3 f_{n-3} fn3 种方案,不然第 3 3 3 位就应该是 U ;
  4. 此时已满足条件,那么剩下 n − 3 n-3 n3 位随便选,得出递推式为:
    f i = f i − 1 + f i − 2 + f i − 3 f_i=f_{i-1}+f_{i-2}+f_{i-3} fi=fi1+fi2+fi3

AC 记录

Code

#include <bits/stdc++.h>
#define int long long
#define AC return 0
#define M(a) memset(a,0,sizeof a)
#define il inline
#define rep(i,l,r) for(int i=l;i<=r;i++)
using namespace std;

const int N=100010;

int f[N];
int n;

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	while(cin>>n && n) {
		M(f);
		f[1]=2; f[2]=4 ;f[3]=7;
		rep(i,4,n) f[i]=f[i-1]+f[i-2]+f[i-3];
		int Ans=pow(2,n)-f[n];
		cout<<Ans<<endl;
	}
	AC;
}

T h e    e n d The \; end Theend

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值