dp[i][j]当前位置为i状态为j的最小代价,超时
考虑到位置这个状态太大,费用很小
dp[i][j]当前状态为i代价为j的最小位置
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<map>
using namespace std;
const int N=5e5+100;
const int M=22;
char ss[M];
int fnext[N][M];
int id[M];
int n;
int aa[N],top;
void pri(int aa[N],int n){
for(int i=0;i<n;i++){
printf("%d%c",aa[i],i==n-1?'\n':' ');
}
}
void getfnext(){
for(int i=0;i<n;i++)id[i]=top;
for(int i=top-1;i>=0;i--){
for(int j=0;j<n;j++){
fnext[i][j]=id[j];
}
id[aa[i]]=i;
}
//pri(id,n);
// for(int i=0;i<top;i++){
// pri(fnext[i],n);
// }
}
int dp[1<<15][15*15];
int ms[25];
int ww[1<<15][15];
int cot[1<<15];
void getms(int n){
for(int i=0;i<n;i++){
ms[i]=1<<i;
}
int ed=1<<n;
cot[0]=0;
for(int i=1;i<ed;i++){
cot[i]=cot[i-(i&-i)]+1;
}
//pri(cot,ed);
for(int i=0;i<ed;i++){
for(int j=0;j<n;j++){
if(i&ms[j])continue;
ww[i][j]=cot[i>>j];
}
}
//printf("%d\n",ww[2][0]);
}
void getdp(){
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<n;i++){
dp[ms[i]][0]=id[i];
}
int ed=1<<n;
for(int i=1;i<ed;i++){
for(int j=0;j<n*n;j++){
if(dp[i][j]>=top)continue;
int x=dp[i][j];
for(int k=0;k<n;k++){
if(i&ms[k])continue;
if(fnext[x][k]>=top)continue;
dp[i|ms[k]][j+ww[i][k]]=min(dp[i|ms[k]][j+ww[i][k]],fnext[x][k]);
}
}
}
}
map<string,int> mp;
void prin(int ans,int idx){
if(ans!=n*n){
printf("%d\n",idx+1);
//printf("%dans\n",ans);
ans=n*(n-1)/2-ans+1;
printf("[:");
while(ans--)printf("|");
printf(":]\n");
}
else {
printf("Brand new problem!\n");
}
}
int main(){
#ifdef DouBi
freopen("in.cpp","r",stdin);
#endif // DouBi
while(scanf("%d",&n)!=EOF){
mp.clear();
for(int i=0;i<n;i++){
scanf("%s",ss);
mp[ss]=i+1;
}
getms(n);
int m;scanf("%d",&m);
int ans=n*n,idx;
for(int i=0;i<m;i++){
int k;scanf("%d",&k);
top=0;
while(k--){
scanf("%s",ss);
if(mp[ss]){
aa[top++]=mp[ss]-1;
}
}
//pri(aa,top);
getfnext();
getdp();
int ed=1<<n;
for(int j=0;j<n*n;j++)if(dp[ed-1][j]<top){
if(j<ans){
ans=j,idx=i;
}
}
}
prin(ans,idx);
}
return 0;
}