zoukankan      html  css  js  c++  java
  • AcWing309 装饰围栏(计数dp+试填法)

    我们想要求某一个真正的序列,很多情况下都是用试填法来求取,填一个数上去看看是否满足条件。

    所以我们要知道以如果填当前数,那么以当前数为首的剩下的数和c的关系。所以我们知道要预处理出所有满足条件的数的个数,也就是计数问题。

    很自然的,前两位要设计为i个数,第一位,也就是最左边这位填的数是第j大,为什么会想到设计最左边,因为我们肯定是从高位开始填,才能每次判断是否已经大于c了。

    我们设计相对位置,因为题目的要求也是相对的大小。

    继而发现信息还不够,因为题目要求高低的关系,所以再多加一维表示,该位是高位还是低位,高位就从i-1的低位转移,反之同理。

    现在考虑转移方程,f[i][j][1]=sum(f[i-1][k][0])这里的k一定要小于j,因为i是高位,反之同理。

    之后就是试填法计算是哪个数,首先要特判第一位,因为第一位是高位还是低位没定,后面的都是相对前一位的状态

    显然先枚举高位,因为这样的数比较小

    还要从小到大枚举x,表示填的数是第几大。因此要st数组记录数有没有被用过。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    ll f[21][21][2];
    int st[21];
    int a[21];
    int n;
    void init(){
        int i,j;
        f[1][1][0]=f[1][1][1]=1;
        int k;
        for(i=2;i<=20;i++){
            for(j=1;j<=i;j++){
                for(k=j;k<i;k++)
                f[i][j][0]+=f[i-1][k][1];
                for(k=1;k<j;k++)
                f[i][j][1]+=f[i-1][k][0];
            }
        }
    }
    int main(){
        int t;
        cin>>t;
        init();
        while(t--){
            ll c;
            cin>>n>>c;
            int i,j;
            int k=0;
            memset(st,0,sizeof st);
            for(i=1;i<=n;i++){
                if(f[n][i][1]>=c){
                    a[1]=i;
                    st[i]=1;
                    k=1;
                    break;
                } 
                else{
                    c-=f[n][i][1];
                }
                if(f[n][i][0]>=c){
                    a[1]=i;
                    st[i]=1;
                    k=0;
                    break;
                }
                else{
                    c-=f[n][i][0];
                }
            }
            for(i=2;i<=n;i++){
                k^=1;
                int cnt=1;
                for(j=1;j<=n;j++){
                    if(st[j])
                    continue;
                    if(k==1&&j>a[i-1]||k==0&&j<a[i-1]){
                        if(f[n-i+1][cnt][k]>=c){
                            st[j]=1;
                            a[i]=j;
                            break;
                        }
                        else
                            c-=f[n-i+1][cnt][k];
                    }
                    cnt++;
                }
            }
            for(i=1;i<=n;i++){
                cout<<a[i]<<" ";
            }
            cout<<endl;
        }
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    vmware ubuntu 异常关机无法连接到网络
    Speed up GCC link
    常用的一些解压命令
    Log4j 漏洞复现
    Test Case Design method Boundary value analysis and Equivalence partitioning
    CCA (Citrix Certified Administrator) exam of “Implementing Citrix XenDesktop 4”
    What is Key Word driven Testing?
    SAP AGS面试小结
    腾讯2013终端实习生一面
    指针的引用
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12715303.html
Copyright © 2011-2022 走看看