hdu4909 状态压缩(偶数字符子串)

题意:
      给你一个字符串,里面最多有一个'?','?'可以表示'a' - 'z',也可以什么都不表
示,这里要明确,什么都不表示不是不存在的意思,当aa什么都不表示的时候aa 也不等于aa? ,因为这个wa的快吐血了,题目要求输出一共有多少个子串满足所有字母('a' -'z')出现的次数必须是偶数个。

思路:

      首先对于每一个前缀串的奇偶状态我们可以用mark[1<<26]的状态压缩表示,如果当前字母的个数是偶数,那么对应位置的状态就是0,奇数是1,先不考虑'?',假如当前的这个状态在之前出现过,那么当前可以增加的子串数量就是当前状态之前出现的次数,为什么是这样呢?两个相同的状态之间肯定是经过了偶数次变化,奇数 + 偶数 = 奇数,偶数 + 偶数 = 偶数,所以说前面有多少个当前状态,就有多少个偶数间隔,就会有几个满足题意的子串,(也可以全求出来,然后排列组合C(m,2))一个意思,现在在把'?'考虑进来,先算出没意义的情况,然后在枚举他是'a' - 'z',枚举的时候我是先枚举一遍以'?'结尾的,然后对于?后面的直接就把每一个状态的每一位都改变一次,求出所有的和就行了,还有要注意的一点就是mark[1<<26]数组很大,memset清不起,我们要采取每次只把用过的清空的原则去减少时间。感觉没说清楚,但这个题目不是很好说明白,自己做了将近一天才AC,要是看不懂就看看代码然后自己在想想吧。


#include<stdio.h>
#include<string.h>

int sum[(1<<26)+10];
int num[22000];
char str[22000];

int main ()
{
   int i ,j ,t ,ans;
   scanf("%d" ,&t);
   while(t--)
   {
      scanf("%s" ,str);
      int len = strlen(str);
      int mki = -1 ,tt = 0;
      num[0] = 0;
      sum[num[0]] = 1;
      for(ans = i = 0 ;i < len ;i ++)
      {
         if(str[i] == '?')        
         {
            mki = i;
            ans += sum[num[tt]];
            sum[num[tt]] ++;
            continue;
         }
         tt ++;
         num[tt] = num[tt-1] ^ (1 << (str[i] - 'a'));
         ans += sum[num[tt]]; 
         sum[num[tt]] ++;
      }
     
      for(i = 0 ;i <= tt ;i ++)
      sum[num[i]] = 0;    
      if(mki == -1)
      {
         printf("%d
" ,ans);
         continue;
      }
      tt = 0;
      num[0] = 0;
      sum[num[0]] = 1;
      for(i = 0 ;i < mki ;i ++)
      {
         tt ++;
         num[tt] = num[tt-1] ^ (1 << (str[i] - 'a'));
         sum[num[tt]] ++;
      }
      
      for(i = 'a' ;i <= 'z' ;i ++)
      {
          int tmp = num[tt] ^ (1 << (i - 'a'));
          ans += sum[tmp];
      }
      
      for(i = mki + 1 ;i < len ;i ++)
      {
         tt ++;
         num[tt] = num[tt-1] ^ (1 << (str[i] - 'a'));
         for(j = 0 ;j < 26 ;j ++)
         ans += sum[num[tt]^(1<<j)];         
      }
      for(int i = 0 ;i <= tt ;i ++)
      sum[num[i]] = 0; 
      printf("%d
" ,ans);
   }
   return 0;
}
      

原文地址:https://www.cnblogs.com/csnd/p/12062903.html