题意:
n
n
n个01串。两个人轮流填0或者1,如果某人填完后某个字符串第一次出现,那么这个字符串的分值加到这个人的总分里面,每个人都要最大化自己的分减去另外一个人的分。每次询问从给定的字符串后面开始填起。
思路:
很明显,首先建立AC自动机,然后用状态压缩。
我们设 d p s t a t u , p dp_{statu,p} dpstatu,p表示现在已经在点 p p p,已经填完的字符串状态是 s t a t u statu statu,接下来先手能得到的最大差。
那么肯定是从大到小枚举 s t a t u statu statu,假设现在的状态为 k i ki ki。
现在难点在于,如果出现了环应该怎么办。
如果走到了某个节点以后,状态会发生改变,那么我们就把这个点设置成确定的。
如果某一个点能走到的点都是确定的,那么显然它也是确定的。
如果不存在前面的点,那么我们就考虑当前能在已经确定一部分的情况下能到达最大的点,再把这个点变成确定的。
#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
#define ll long long
using namespace std;
template<typename T>inline void qr(T &x){
x=0;int f=0;char s=getchar();
while(!isdigit(s))f|=s=='-',s=getchar();
while(isdigit(s))x=x*10+s-48,s=getchar();
x=f?-x:x;
}
int cc=0,buf[31];
template<typename T>inline void qw(T x){
if(x<0)putchar('-'),x=-x;
do{buf[++cc]=int(x%10);x/=10;}while(x);
while(cc)putchar(buf[cc--]+'0');
}
const int N=160,inf=1e9;
int n,len;char s[N];
int cnt=1,ch[N][2],fail[N],pos[N],statu[N],statu2[N];
int dp[1<<18][N];
vector<int>e[N];int deg[N];
int d[N];
int value[1<<18];
bool v[N];
void add(int id){
int p=1;
rep(i,1,len){
int w=s[i]-'0';
if(!ch[p][w])ch[p][w]=++cnt;
p=ch[p][w];
}
pos[id]=p;
statu[p]|=1<<(id-1);
statu2[p]=statu[p];
}
void getfail(){
rep(i,0,1)ch[0][i]=1;
queue<int>q;q.push(1);
while(q.size()){
int x=q.front();q.pop();
int fa=fail[x];
statu2[x]|=statu2[fa];
rep(i,0,1){
int y=ch[x][i];
if(!y){ch[x][i]=ch[fa][i];continue;}
fail[y]=ch[fa][i];
q.push(y);
}
}
}
void solve(){
qr(n);
int lim=(1<<n)-1;
rep(i,1,n){
scanf("%s",s+1);
len=strlen(s+1);
add(i);
int v;qr(v);
rep(j,0,lim)if(j>>(i-1)&1)value[j]+=v;
}
getfail();
rep(i,1,cnt){
rep(w,0,1){
if(ch[i][w]){
e[ch[i][w]].push_back(i);
}
}
}
dwn(ki,lim-1,0){
rep(i,1,cnt){
d[i]=-inf;
deg[i]=2;
v[i]=0;
}
queue<int>q;
priority_queue<pair<int,int> >Q;
rep(x,1,cnt){
if((statu2[x]|ki)>ki){
for(int y:e[x])if((statu2[y]|ki)==ki){
if(d[y]<value[statu2[x]^(statu2[x]&ki)]-dp[ki|statu2[x]][x]){
d[y]=value[statu2[x]^(statu2[x]&ki)]-dp[ki|statu2[x]][x];
Q.push({d[y],y});
}
if(!--deg[y])q.push(y);
}
}
}
while(q.size()||Q.size()){
if(q.size()){
while(q.size()){
int x=q.front();q.pop();
if(v[x])continue;
v[x]=1;
dp[ki][x]=d[x];
for(int y:e[x])if((statu2[y]|ki)==ki&&!v[y]){
if(d[y]<-d[x]){
d[y]=-d[x];
Q.push({d[y],y});
}
if(!--deg[y])q.push(y);
}
}
}
else{
if(Q.size()){
int x=Q.top().second;Q.pop();
if(v[x])continue;
if(d[x]<=0)break;
q.push(x);
}
}
}
}
int q;qr(q);
while(q--){
scanf("%s",s+1);
len=strlen(s+1);
int p=1,now=statu2[1];
rep(i,1,len){
int w=s[i]-'0';
p=ch[p][w];
now|=statu2[p];
}
qw(dp[now][p]),puts("");
}
}
int main(){
int tt;tt=1;
while(tt--)solve();
return 0;
}