计数原理,递推,求从左边能看到l个棒子,右边能看到r个棒子的方案数目

题意

有高为 1, 2, …, n 的 n 根杆子排成一排, 从左向右能看到 L 根, 从右向左能看到 R 根。求有多少种可能的排列方式。

solution:

数据范围仅200,本来是往组合数学方面想的,看到了这个200就放弃了念头,果然是dp

定义dp[i][j][k]是用了高度为1~i的杆子,从左边能看到j个,从右边能看到k个

如果从1转移到n很困难,因为放一个高的杆子进去会造成很多的遮挡影响,是几乎不能维护的。于是考虑从n转移到1,即先放比较高的杆子

加上放好了2~n高度的杆子,再放高度为1的杆子仅有三种情况

1.放在最左边。仅仅是从左看能多看到一个 dp[i][j][k]+=dp[i-1][j-1][k]

2.放在最右边,同理

3.放在中间,一定会被挡住。i-1根杆子间有(i-2)个,则dp[i][j][k]+=dp[i-1][j][k]*(i-2)。

其实这里i的定义已经发生了一点变化,但是状态转移是很容易理解的

为什么可以把i等效定义为i个,而不是1~i呢?其实这只需要代表是i根高度不同的杆子,2~i的杆子全部砍1,相对高度没有变,也就等效成了1~i-1的杆子

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 #include<cstring>
 7 #define mp make_pair
 8 #define pb push_back
 9 #define first fi
10 #define second se
11 #define pw(x) (1ll << (x))
12 #define sz(x) ((int)(x).size())
13 #define all(x) (x).begin(),(x).end()
14 #define rep(i,l,r) for(int i=(l);i<(r);i++)
15 #define per(i,r,l) for(int i=(r);i>=(l);i--)
16 #define FOR(i,l,r) for(int i=(l);i<=(r);i++)
17 #define eps 1e-9
18 #define PIE acos(-1)
19 #define cl(a,b) memset(a,b,sizeof(a))
20 #define fastio ios::sync_with_stdio(false);cin.tie(0);
21 #define lson l , mid , ls
22 #define rson mid + 1 , r , rs
23 #define ls (rt<<1)
24 #define rs (ls|1)
25 #define INF 0x3f3f3f3f
26 #define LINF 0x3f3f3f3f3f3f3f3f
27 #define freopen freopen("in.txt","r",stdin);
28 #define cfin ifstream cin("in.txt");
29 #define lowbit(x) (x&(-x))
30 #define sqr(a) a*a
31 #define ll long long
32 #define ull unsigned long long
33 #define vi vector<int>
34 #define pii pair<int, int>
35 #define dd(x) cout << #x << " = " << (x) << ", "
36 #define de(x) cout << #x << " = " << (x) << "\n"
37 #define endl "\n"
38 using namespace std;
39 //**********************************
40 ll dp[25][25][25];//dp[i][j][k]表示i个棒子从左边能看到j个右边能看到k个的方案数
41 //**********************************
42 void Init()
43 {
44     dp[1][1][1]=1;
45     FOR(i,2,20)FOR(j,1,i)FOR(k,1,i-j+1)dp[i][j][k]=dp[i-1][j-1][k]+dp[i-1][j][k-1]+dp[i-1][j][k]*(i-2);
46 }
47 //**********************************
48 int main()
49 {
50     Init();
51     int T;cin>>T;
52     while(T--){
53         int a,b,c;cin>>a>>b>>c;
54         cout<<dp[a][b][c]<<endl;
55     }
56     return 0;
57 }

原文地址:https://www.cnblogs.com/klaycf/p/9689467.html

时间: 2024-10-08 06:46:08

计数原理,递推,求从左边能看到l个棒子,右边能看到r个棒子的方案数目的相关文章

递推求值【快速幂矩阵】

递推求值 描述 给你一个递推公式: f(x)=a*f(x-2)+b*f(x-1)+c 并给你f(1),f(2)的值,请求出f(n)的值,由于f(n)的值可能过大,求出f(n)对1000007取模后的值. 注意:-1对3取模后等于2   输入 第一行是一个整数T,表示测试数据的组数(T<=10000)随后每行有六个整数,分别表示f(1),f(2),a,b,c,n的值.其中0<=f(1),f(2)<100,-100<=a,b,c<=100,1<=n<=10000000

NYOJ-301递推求值

递推求值 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给你一个递推公式: f(x)=a*f(x-2)+b*f(x-1)+c 并给你f(1),f(2)的值,请求出f(n)的值,由于f(n)的值可能过大,求出f(n)对1000007取模后的值. 注意:-1对3取模后等于2 输入 第一行是一个整数T,表示测试数据的组数(T<=10000)随后每行有六个整数,分别表示f(1),f(2),a,b,c,n的值.其中0<=f(1),f(2)<100,-100<=

NYOJ——301递推求值(矩阵快速幂)

递推求值 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 给你一个递推公式: f(x)=a*f(x-2)+b*f(x-1)+c 并给你f(1),f(2)的值,请求出f(n)的值,由于f(n)的值可能过大,求出f(n)对1000007取模后的值. 注意:-1对3取模后等于2 输入 第一行是一个整数T,表示测试数据的组数(T<=10000) 随后每行有六个整数,分别表示f(1),f(2),a,b,c,n的值. 其中0<=f(1),f(2)<100,-100<=

递推求欧拉函数的最简单的详解

有以下的两条性质: if(gcd(i, prime[j]) == 1) phi[i * prime[j]] = phi[i] * phi[prime[j]]; //因为是积性函数.phi[prime[j]]其实就是prime[j]-1. else phi[i * prime[j]] = phi[i] * prime[j];  所以,可以模仿埃氏筛的方法,来进行递推,顺便同时求出素数表. F(i, 1, n) phi[i] = i; //相当于not_prime[]的作用 F(i, 1, n) {

poj 2096 Collecting Bugs 【概率DP】【逆向递推求期望】

Collecting Bugs Time Limit: 10000MS   Memory Limit: 64000K Total Submissions: 3523   Accepted: 1740 Case Time Limit: 2000MS   Special Judge Description Ivan is fond of collecting. Unlike other people who collect post stamps, coins or other material s

【poj2478-Farey Sequence】递推求欧拉函数-欧拉函数的几个性质和推论

http://poj.org/problem?id=2478 题意:给定一个数x,求<=x的数的欧拉函数值的和.(x<=10^6) 题解:数据范围比较大,像poj1248一样的做法是不可行的了. 首先我们要了解欧拉函数的几个性质和推论:(今天跟好基友Konjak魔芋讨论了好久..) 推论(一): phi(p^k)=(p-1)*p^(k-1) 证明: 令n=p^k,小于等于n的正整数数中,所有p的倍数共有p^k /p = p^(k-1)个. 1~n出去p的倍数,所以phi(n)= n -  p^

蓝桥杯 算法提高 递推求值

思路: 矩阵快速幂. 实现: 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 using namespace std; 5 6 typedef long long ll; 7 typedef vector<ll> vec; 8 typedef vector<vec> mat; 9 10 const int mod = 99999999; 11 12 mat mul(m

UVa 1638 Pole Arrangement【递推】

题意:给出n根高度为1,2,3,---n的杆子,从左边能看到l根,右边能够看到r根,问有多少种可能 看的紫书的思路 先假设已经安排好了高度为2---i的杆子, 那么高度为1的杆子的放置方法有三种情况 放在最左边:从左边看得见,右边看不见 放在最右边:从右边看得见,左边看不见 放在中间,有i-2个空位可以插,左右都看不见 所以可以写出递推关系: d[i][j][k]=d[i-1][j-1][k]+d[i-1][j][k-1]+d[i-1][j][k]*(i-2); 1 #include<iostr

CodeForces 372B 脑洞大开的DP递推

题目: 做了两个多小时,脑洞大开,给了一个01矩阵,求以a,b,为左上角,c,d为右下角的矩阵内有多少包含部分全为0的子矩阵 对于这道题目,一开始就想到了DP递推,感觉而已,虽然准,可是做不出啊,想好了递推式子可是细节部分没办法去处理.看了CF上的题解,顿时脑洞大开,这个做法真的是太厉害了,这方法代码简洁明了,同时也提醒到了我,在方程假设出来后,对于转移的细节处理, 其实一开始我想到过这个递推式子 dp[i][j][k][l] += dp[i][j][k - 1][l] + dp[i][j][k