题目:https://cn.vjudge.net/problem/Gym-101612C
题意:给出一个字符串(长度不超过1e6),仅由小写字母组成。定义一个叫consonant fencity的东西,含义是如果两个连续字母是辅音(本题中辅音指除aeiouwy以外的字母),且大小写不相同,就有一对consonant fencity。题目要求指定每个字母的大小写形式(要求相同字母的大小写形式相同),输出consonant fencity最多的字符串。
思路:显然可以枚举每种字母的大小写形式的组合来求解,但直接枚举再计算的复杂度高达O(n * 2^19),这显然没法接受。考虑到辅音字母是固定的,可以每种辅音字母看作一个结点,将字符串中存在两个字母构成consonant fencity看作有一条从在前的字母到在后的字母的有向边,将这两个字母构成consonant fencity的次数看作边权建图,再用二进制枚举计算时直接扫图即可求解,这样复杂度就降到了O(n)的预处理+19*19*2^19大概1.9e8,对于3秒的时间可以接受。
代码:C++
这里我用bitset进行二进制枚举,当然也可以用位运算
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
#include <bitset>
#include <cmath>
using namespace std;
const int maxn = 1000000 + 10;
const int maxm = 19;
const char consonants[20] = "bcdfghjklmnpqrstvxz";
int toint[200];
char s[maxn];
int len;
int pic[maxm][maxm];
int maxx = 0;
int maxstatus = 0;
bool isconsonant(char c)
{
return !(c == 'a' || c == 'e' || c == 'i'|| c == 'o' || c == 'u' || c == 'w' || c == 'y');
}
void init()
{
for(int i = 0; i < 19; i++)
{
toint[consonants[i]] = i;
}
}
void buildpic()
{
for(int i = 0; i < len - 1; i++)
{
if(isconsonant(s[i]) && isconsonant(s[i+1]))
{
pic[toint[s[i]]][toint[s[i+1]]]++;
}
}
}
int solve(bitset<32> st)
{
int ans = 0;
for(int i = 0; i < maxm; i++)
{
for(int j = 0; j < maxm; j++)
{
if(pic[i][j] && st[i] ^ st[j])
{
ans += pic[i][j];
}
}
}
return ans;
}
int main()
{
freopen("consonant.in", "r", stdin);
freopen("consonant.out", "w", stdout);
scanf("%s", s);
len = strlen(s);
init();
buildpic();
int statusnum = 1 << 19;
for(int i = 0; i < statusnum; i++)
{
int t = solve(bitset<32>((unsigned int)i));
if(t > maxx)
{
maxx = t;
maxstatus = i;
}
}
bitset<32> ans((unsigned)maxstatus);
for(int i = 0; i < len; i++)
{
if(ans[toint[s[i]]])
{
putchar(toupper(s[i]));
}
else
{
putchar(s[i]);
}
}
return 0;
}