In a contest like the one you are participating in currently, a verdict of Accepted means that your solution was run on all test cases and produced the correct output for them all. However, some popular websites that hold online rounds prefer to use a pretest system. Your solution would be run on a subset of the test cases when you submit it, otherwise known as pretests.
For a problem with t pretests, solutions are judged on them in order, one by one, until it fails to produce a correct output. So, if a solution fails on the kth test, it will request k test runs, and if it never fails, it will request t test runs.
To prevent the system from lagging, it would be preferable if the total number of test runs for all submissions was minimized.
You are given the verdicts of n submissions on each of the t pretest cases.
Print the minimum total number of runs needed if the pretests were ordered optimally. If there is more than one order that minimizes the answer, print the lexographically smallest one.
Input
The first line of input contains a single integer P, the number of problems you are ordering the pretests for.
The first line for each of the P problems contains two space-separated integers t and n (1 ≤ t ≤ 20) (1 ≤ n ≤ 2 × 105), the number of pretests for this problem and the number of submissions, respectively.
Each of the following n lines contains t characters representing the verdicts of this submission on each of the pretests, the ith character is ‘1’ if this submission passes the ith pretest, or ‘0’ if it fails.
Output
For each of the P problems, output two lines. On the first line, print the minimum total number of test runs needed if the pretests were ordered optimally.
On the second line, print a permutation of the numbers from 1 to t, representing the lexographically smallest order of the pretests that produces the minimum answer.
Example
inputCopy
1
4 3
1100
0101
0011
outputCopy
4
1 3 2 4
Note
A permutation a is lexicographically smaller than permutation b if there exists an index i such than ai < bi and aj = bj for all (1 ≤ j < i).
题意:
有n个人,每个人交了一道题,这道题有t个测试点,0代表这个人没过这个测试点,没过测试点就不会判下一个测试点,1代表过了。让你重组测试点的顺序,使得所有人判题的次数的和最小,无论这个测试点是否过了都算判1次。
题解:
本来是用bitset暴力做的,但是好像bitset赋值会把时间搞炸掉,,讲题的时候才知道用高维前缀和:
for(int i=0;i<n;i++)
for(int j=(1<<n)-1;j>=0;j--)
if(j&(1<<i))
num[j^(1<<i)]+=num[j];
表示在j这个状态的时候,需要判第i个测试点的人数。
dfs是一个记忆化搜索,
dfs(x|(1<<i))+num[x]
表示x这个状态的时候,过了i这个测试点时需要判num[x]个人
#include<bits/stdc++.h>
using namespace std;
int dp[(1<<20)],num[(1<<20)];
int a[25];
int n,m;
int dfs(int x)
{
int &ans=dp[x];
if(~ans)
return ans;
ans=1e9;
for(int i=0;i<n;i++)
if(!(x&(1<<i)))
ans=min(ans,dfs(x|(1<<i))+num[x]);
//cout<<ans<<endl;
return ans;
}
int main()
{
freopen("tests.in","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<=(1<<n);i++)
num[i]=0;
for(int i=1;i<=m;i++)
{
int x=0;
for(int j=0;j<n;j++)
{
scanf("%1d",&a[j]);
if(a[j]&1)
x|=(1<<j);
}
num[x]++;
}
for(int i=0;i<=(1<<n);i++)
dp[i]=-1;
dp[(1<<n)-1]=0;
for(int i=0;i<n;i++)
for(int j=(1<<n)-1;j>=0;j--)
if(j&(1<<i))
num[j^(1<<i)]+=num[j];
printf("%d\n",dfs(0));
int now=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<n;j++)
{
if(now&(1<<j))
continue;
if(dfs(now|(1<<j))+num[now]==dfs(now))
{
now|=(1<<j);
printf("%d ",j+1);
break;
}
}
}
printf("\n");
}
return 0;
}