• [2022天梯赛] 教科书般的亵渎 【记忆化搜索】【剪枝】


    题目描述:

    $n$张牌每个牌有权值$a_i$,要求选择$k$次,每次让牌的权值减一,使得牌的权值形成从$1$开始的连续整数(不含$0$).

    $n,k,ai \leq 50$

    分析:

    先考虑朴素dp,先将$a_i$排序,$dp[i][S][j]$表示前$i$个数,把$S$这些位填上了,还剩$j$次行动机会的方案数。有

    $$dp[i][S][j] -> dp[i+1][S|(1<<k)][j-(a_i-k+1)]$$

    考虑剪枝,如果$S$加上后面还没用的$a_i$在操作数最小且形成连续整数的情况下仍然比能用的次数$j$要大,则剪去。用unorderedmap存状态。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 60;
     5 const int mod = 998244353;
     6 
     7 int n,k;
     8 int a[maxn];
     9 
    10 int C[maxn][maxn];
    11 int ans;
    12 unordered_map <unsigned long long,int> mp[2][52],imm;
    13 struct node{
    14     int kk;
    15     unsigned long long now;
    16 };
    17 queue<node> q[2];
    18 
    19 bool pd(node fa,int i){
    20     int dj = 0;
    21     for(;i<=n;i++){
    22     unsigned long long pj = (fa.now+1)&(~fa.now);
    23     if((1ull<<a[i]-1)<pj) continue;
    24     int pp = imm[pj];
    25     dj += a[i]-pp;
    26     if(dj > fa.kk) return 0;
    27     fa.now += pj;
    28     }
    29     return 1;
    30 }
    31 
    32 int fast_pow(int now,int pw){
    33     int ans = 1,dt = 1;
    34     while(dt <= pw){
    35     if(dt & pw) ans = 1ll*ans*now%mod;
    36     dt<<=1;
    37     now = 1ll*now*now%mod;
    38     }
    39     return ans;
    40 }
    41 
    42 int cnt = 0;
    43 void dfs(int now,unsigned long long st,int num,int way){
    44     if(now > n){
    45     if(num != 0) return;
    46     int flag = imm.count(st+1);
    47     if(!flag) return;
    48     ans += way;
    49     if(ans >= mod) ans -= mod;
    50     }else{
    51     for(int i=a[now];i>=1;i--){
    52         if(a[now]-i > num) break;
    53         unsigned long long bt = st|(1ull<<i-1);
    54         int sz = num-(a[now]-i);
    55         int tms = 1ll*way*C[num][a[now]-i]%mod;
    56         int zz = (now+1)&1;
    57         if(now == n){dfs(now+1,bt,sz,tms);continue;}
    58         if(!pd((node){sz,bt},now+1)) continue;
    59         if(mp[zz][sz].count(bt)){
    60         mp[zz][sz][bt]=(mp[zz][sz][bt]+tms)%mod;
    61         }else {
    62         q[zz].push((node){sz,bt});
    63         mp[zz][sz][bt] = tms;
    64         }
    65     }
    66     }
    67 }
    68 
    69 
    70 int main(){
    71     ios::sync_with_stdio(false);
    72     cin >> n >> k;
    73     for(int i=0;i<=50;i++){
    74     unsigned long long u = 1ull<<i;
    75     imm[u] = i+1;
    76     }
    77     for(int i=0;i<=k;i++){
    78     C[i][0] = C[i][i] = 1;
    79     for(int j=1;j<i;j++) C[i][j] = (C[i-1][j-1]+C[i-1][j])%mod;
    80     }
    81     for(int i=1;i<=n;i++) cin >> a[i];
    82     sort(a+1,a+n+1);
    83     mp[1][k][0] = 1; q[1].push((node){k,0});
    84     for(int i=1;i<=n;i++){
    85     for(int j=0;j<=k;j++) mp[(i&1)^1][j].clear();
    86     //cnt=0;
    87     while(!q[i&1].empty()){
    88         //cnt++;
    89         node kd = q[i&1].front(); q[i&1].pop();
    90         dfs(i,kd.now,kd.kk,mp[i&1][kd.kk][kd.now]);
    91     }
    92     //cout<<cnt<<endl;
    93     }
    94     cout<<1ll*ans*fast_pow(fast_pow(n,k),mod-2)%mod<<endl;
    95     return 0;
    96 }
    View Code
  • 相关阅读:
    OM Shipping 授权
    Account Summary 汇总模板
    OM Record is currently being worked on by another user, Please try to update it later.
    Initialization SQL Statement – Custom 配置错误,导致无法加载FORM
    ReOpen a Closed Inventory Accounting Period [ID 472631.1]
    IBM AIX User Lists
    Killing Oracle Sessions
    APPFND01016 (GL > Setup > Flexfields > Key > Rules)
    OM: release hold的时候,又遇到限制:You are not authorized to release this hold.
    SO History
  • 原文地址:https://www.cnblogs.com/Menhera/p/16193090.html
Copyright © 2020-2023  润新知