• 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
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    C# Linq 类似Scala中的map的函数
    Spark DataFrame NOT IN实现方法
    Scala scopt 命令行解析
    WPF 绑定到静态属性,可通知
    WPF GroupBox Header居中
    WPF开源项目整理(排名不分先后)
    Windows 上配置 Go 的 gRPC 编译环境
    C++20新线程 jthread 体验代码
    查找被删除但仍然占据磁盘的文件
    以Docker方式安装Redis集群
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12715303.html
Copyright © 2020-2023  润新知