• 计数原理,递推,求从左边能看到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 }
    View Code
  • 相关阅读:
    C++中析构函数的作用,
    fp = fopen(s, "at") 中at 是啥意思,a 是append 追加的意思
    C++中 :: 的意思
    sed 指令
    make -e install ,,,make命令的-e选项!
    _AR="ar" _ARFLAGS="-ruv"
    gcc的-D和-U参数:宏的设置与取消 _CCFLAGS=" -w -enable-threads=posix -DLINUX -D_REENTRANT -DWORKONGN -Dlinux -D_GN_DETAIL_SDR_"
    GCC 编译详解
    RPC 编程 使用 RPC 编程是在客户机和服务器实体之间进行可靠通信的最强大、最高效的方法之一。它为在分布式计算环境中运行的几乎所有应用程序提供基础。
    vim插件ctags的安装和使用
  • 原文地址:https://www.cnblogs.com/klaycf/p/9689467.html
Copyright © 2020-2023  润新知