F. Pretests(状压dp 记忆化搜索 高维前缀和)

原题: http://codeforces.com/gym/102006/problem/F

题意:

l l 个测试点,n发提交。给出每一发提交对应每个测试点的正确性,问怎么样组织测试点使测试次数最少。(错误点的后序测试点不会测试)多个答案输出字典序最小的那个。

解析:

用dp[11100]表示已经使用第3、4、5个测试点的最少测试数。当dp[11100]转移到dp[11101]时,需要增加的为:所有成功到达11100的提交数量(即11100、11110、11101、11111)。

用ct[11100]记录上面的情况,这个要用到高维前缀和:

rep(j,0,l-1){
  repp(i,(1<<l)-1,0){
        if(i&(1<<j))continue;
        ct[i]+=ct[i|(1<<j)];
    }
}

注意第一维要遍历位,第二维遍历状态。因为按照状态单调顺序不能保证位的递增(011->100)

顺序的话就是在得到答案的基础上,从小到大枚举位,看看是否可以从那边转移。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define repp(i,b,a) for(int i=(int)(b);i>=(int)(a);i--)
const int maxn=2e6+6;
int l,n;
int a[maxn],dp[maxn],ct[maxn];
int dfs(int sta){
    if(dp[sta]!=1e9)return dp[sta];
    rep(i,0,l-1){
        if(!(sta&(1<<i))){
            int to=sta|(1<<i);
            dp[sta]=min(dp[sta],dfs(to)+ct[sta]);
        }
    }
    return dp[sta];
}

int main(){
    freopen("tests.in","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        cin>>l>>n;
        rep(i,0,(1<<l)-1)dp[i]=1e9,ct[i]=0;
        dp[(1<<l)-1]=0;
        // dp[101]表示已经用了第1和第3个的情况
        rep(i,1,n){
            string x;cin>>x;
            int sta=0;
            rep(j,0,x.length()-1){
                if(x[j]=='1')sta|=(1<<j);
            }
            ct[sta]++;
        }
        rep(j,0,l-1){
            repp(i,(1<<l)-1,0){
                if(i&(1<<j))continue;
                ct[i]+=ct[i|(1<<j)];
            }
        }
        int ans=dfs(0);
        cout<<ans<<endl;
        int sta=0;
        vector<int>V;
        while(1){
            //printf("dp[%d]=%d\n",sta,dp[sta]);
            rep(i,0,l-1){
                if(!(sta&(1<<i))){
                    int to=sta|(1<<i);
                    if(dp[sta]==dp[to]+ct[sta]){
                        V.push_back(i+1);
                        sta=to;
                        break;
                    }
                }
            }
            if(sta==(1<<l)-1)break;
        }
        rep(i,0,V.size()-1){
            cout<<V[i]<<(i==V.size()-1?'\n':' ');
        }
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/89301957
今日推荐