zoukankan      html  css  js  c++  java
  • uvalive 2965 Jurassic Remains

    https://vjudge.net/problem/UVALive-2965

     题意:

    给出若干个由大写字母组成的字符串,要求选出尽量多的字符串,使得每个大写字母出现的次数是偶数。

    思路:

    如果说我们把每个字母映射为不同的数字,那么每个字符串就可以用不同的数字来表示,即按照二进制位转化各个字符。

    如ABCD既可以表示为1111,ABCE可以表示为11101。

    那么问题就转化成了给出n个数字,那么选择尽量多的数字使得他们的异或为0(每个字符出现偶数次,则他们的异或肯定为0)。

    一开始我直接用的2^N的状态压缩但是t了,参考了训练指南,之后复杂度降为1.414^(N) * log(N)。

    先把前n/2个数可以得到的数字用一个map存起来,之后枚举后面n - n/2个数可以得到的结果,直接在map里面寻找位数尽量大的就可以了。

    求一个数的二进制位有多少个1,这题十分巧妙的用了二分。

    代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <vector>
     4 #include <map>
     5 using namespace std;
     6 
     7 int a[30];
     8 
     9 vector<int> rec;
    10 map<int,int> mmp;
    11 
    12 int calbit(int x)
    13 {
    14     if (x == 0) return 0;
    15 
    16     return calbit(x / 2) + (x & 1);
    17 }
    18 
    19 int main()
    20 {
    21     int n;
    22 
    23     while (scanf("%d",&n) != EOF)
    24     {
    25         mmp.clear();
    26         rec.clear();
    27 
    28         for (int i = 0;i < n;i++)
    29         {
    30             int tmp = 0;
    31 
    32             char b[30];
    33 
    34             scanf("%s",b);
    35 
    36             for (int j = 0;j < strlen(b);j++)
    37             {
    38                 tmp ^= (1 << (b[j] - 'A'));
    39             }
    40 
    41             a[i] = tmp;
    42         }
    43 
    44         int n1 = n / 2;
    45         int n2 = n - n1;
    46 
    47         for (int i = 0;i < (1 << n1);i++)
    48         {
    49             int tmp = 0;
    50 
    51             for (int j = 0;j < n1;j++)
    52             {
    53                 if (i & (1 << j)) tmp ^= a[j];
    54             }
    55 
    56             if (mmp.find(tmp) != mmp.end() || calbit(mmp[tmp]) < calbit(i)) mmp[tmp] = i;
    57         }
    58 
    59         int ans = 0;
    60 
    61         for (int i = 0;i < (1 << n2);i++)
    62         {
    63             int tmp = 0;
    64 
    65             for (int j = 0;j < n2;j++)
    66             {
    67                 if (i & (1 << j)) tmp ^= a[n1+j];
    68             }
    69 
    70             if (mmp.find(tmp) != mmp.end())
    71             {
    72                 if (calbit(i) + calbit(mmp[tmp]) > calbit(ans)) ans = mmp[tmp] ^ (i << n1);
    73             }
    74         }
    75 
    76         for (int i = 0;i < n;i++)
    77         {
    78             if (ans & (1 << i)) rec.push_back(i);
    79         }
    80 
    81         printf("%d
    ",rec.size());
    82 
    83         for (int i = 0;i < rec.size();i++)
    84         {
    85             printf("%d%c",rec[i] + 1,i == rec.size() ? '
    ': ' ');
    86         }
    87 
    88         printf("
    ");
    89     }
    90 
    91     return 0;
    92 }
  • 相关阅读:
    IntelliJ IDEA错误: 源值1.5已过时,将在未来所有版本中删除
    AcWing 311. 月之谜 数位dp
    AcWing 306. 杰拉尔德和巨型象棋 计数类DP
    AcWing 296. 清理班次2 线段树优化dp
    luogu P3052 [USACO12MAR]Cows in a Skyscraper G
    luogu P5664 Emiya 家今天的饭 容斥+dp
    AcWing 289. 环路运输 滑动窗口单调队列优化
    AcWing 288. 休息时间 滚动数组+分类讨论
    AcWing 287. 积蓄程度 树形dp,换根
    luogu P3842 [TJOI2007]线段 线性dp
  • 原文地址:https://www.cnblogs.com/kickit/p/7677977.html
Copyright © 2011-2022 走看看