ABC199E 题解

E - Permutation

考场上因为没时间了没做出来……主要是 C 题脑抽了
(没事,前面几场失误不要紧,反正不可能让你 Rating 一下子冲天。今后吸取教训就好)


状压 dp。
我们设 \text{dp}_{sta} 表示当前选择的数的状态有多少种情况。

  1. 如果没有题目中的条件约束,\text{dp}_0=1\text{dp}_i= \sum \text{dp}_j (其中 ji 的子集且只相差一个元素)。初步转移方程列好。
  2. 判断条件约束。如果当前已经选择了 x_i 个元素,并且状态下 \leq y_i 的值 >z_i ,该状态下 \text{dp}_{sta}=0 。我们先用一个数组表示一个状态每一位上是否是 1,并求个前缀和,判断时会方便很多。

代码:

#include<iostream>
#include<vector>
using namespace std;
#define int long long
int dp[1<<20],n,m,x[110],y[110],z[110],tmp[110];
bool ok[1<<20];
signed main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>x[i]>>y[i]>>z[i];
    }
    dp[0]=1;
    for(int i=1;i<(1<<n);i++){
        for(int j=0;j<n;j++){
            if(i&(1<<j)) tmp[j]=1;
            else tmp[j]=0;
        }
        for(int j=1;j<n;j++){
            tmp[j]+=tmp[j-1];
        }//求前缀和
        bool flag=true;
        for(int j=1;j<=m;j++){
            if(tmp[n-1]==x[j]&&tmp[y[j]-1]>z[j]){
                flag=false;
            }//注意 tmp[n-1]==x[j] 不能落下,位数要匹配
        }
        ok[i]=flag;
    } // 判断
    dp[0]=1;
    for(int i=1;i<(1<<n);i++){
        if(!ok[i]) continue;
        for(int j=0;j<n;j++){
            if((i&(1<<j))==(1<<j))
                dp[i]+=dp[i-(1<<j)];
        }
    }
    cout<<dp[(1<<n)-1]<<endl;// 状压 dp
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容