计数原理,递推,求从左边能看到l个棒子,右边能看到r个棒子的方案数目
Posted 牛奶加咖啡~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计数原理,递推,求从左边能看到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) << " " 37 #define endl " " 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 }
以上是关于计数原理,递推,求从左边能看到l个棒子,右边能看到r个棒子的方案数目的主要内容,如果未能解决你的问题,请参考以下文章