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;
}
posted @ 2019-09-14 22:07  水题收割者  阅读(139)  评论(0编辑  收藏  举报