EZOJ #387字符串
分析
似乎ttl的模拟赛t3总是折半搜索?
先把所有串转化为每个字母的0/1状态
之后我们将所有字符串分为两半
分别枚举状态
我们发现只有左右两边的字母状态相等才能保证这个集合合法
所以我们在搜左半边的时候每次加入一个pair
表示异或值为x用了y个数
搜完后先将它排序
然后搜右边的时候每次lower_bound一下即可
似乎ttl的数据比较强我的代码常数又很大,所以要开O2才能过/kk
代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pi pair<int,int>
#define int long long
pi a[(1<<20)+5];
int ans,wh[110],n,m,sum[30],cnt1,mx;
char s[11000];
inline void dfs1(int p,int lim,int now,int tot){
if(p>lim){
a[++cnt1]=mp(now,tot);
return;
}
dfs1(p+1,lim,now^wh[p],tot+1);
dfs1(p+1,lim,now,tot);
return;
}
inline void dfs2(int p,int lim,int now,int tot){
if(p>lim){
pi *le=lower_bound(a+1,a+cnt1+1,mp(now,-1ll));
pi *ri=lower_bound(a+1,a+cnt1+1,mp(now+1,-1ll));
ans+=(ri-le);
ri--;
if((ri->fi)==now)mx=max(mx,(ri->se)+tot);
return;
}
dfs2(p+1,lim,now^wh[p],tot+1);
dfs2(p+1,lim,now,tot);
return;
}
signed main(){
int i,j,k;
scanf("%lld",&n);
for(i=1;i<=n;i++){
memset(sum,0,sizeof(sum));
scanf("%s",s);
m=strlen(s);
for(j=0;j<m;j++)sum[s[j]-'a']^=1;
for(j=0;j<26;j++)
wh[i]|=((1<<j)*sum[j]);
}
dfs1(1,n/2,0,0);
sort(a+1,a+cnt1+1);
dfs2(n/2+1,n,0,0);
printf("%lld %lld\n",ans-1ll,mx);
return 0;
}