• 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;
    }
          
    

  • 相关阅读:
    Object-Oriented Programming Summary Ⅱ
    Object-Oriented Programming Summary Ⅰ
    自己查与写的批量比较bash
    C#可为空引用类型 -0007
    C#类型系统 -0006
    C#类型 -0005
    C# Main方法返回值 -0004
    C# Main方法参数 -0003
    C# Main方法 -0002
    C# Hello World -0001
  • 原文地址:https://www.cnblogs.com/csnd/p/12062904.html
Copyright © 2020-2023  润新知