http://codeforces.com/gym/101612/attachments
题意:是给定你一串字符,分为元音字母和辅音字母,将辅音字母变成大写,要构成尽量多的大写字母和小写字母的组合,最后输出改变后的字符串。
思路:
由于辅音字母的数量才19个,少到可以状态压缩,将相邻点建边,边权为1,这样可以将字符串转化为1个图,相邻字符的出现次数可以表现为图的权值,然后用二进制去枚举每一种状态,然后内层去找每一步状态得到的权值,当权值最大时,保留状态,最后将所有状态为1的点改为大写,输出。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
freopen("consonant.in","r",stdin);
freopen("consonant.out","w",stdout);
string s;
cin>>s;
char vowel[]= {'a','e','i','o','u','w','y'};
int vis1[500];
int vis2[500];
int vis[500];
int a[500][500];
memset(a,0,sizeof(a));
for(int i=0; i<7; i++) {
vis1[vowel[i]]=1;
}
int z=0;
for(int i='a'; i<='z'; i++) {
if(!vis1[i]) {
vis2[i]=z++;
}
}
for(int i=0; s[i+1]; i++) {
a[s[i]][s[i+1]]++;
}
ll maxx=0,flag=0;
for(ll t=0; t<(1<<19); t++) {
ll sum=0;
for(ll i='a'; i<='z'; i++) {
if(vis1[i])
continue;
ll x=vis2[i];
for(ll j='a'; j<='z'; j++) {
if(vis1[j])
continue;
ll y=vis2[j];
// if(((t>>x)&1)!=((t>>y)&1)) // 1
// ((1<<x)&t)!=((1<<y)&t) 2
// 这两个等式不是等价的 因为 1式 只会返回1或者0 2式可能返回大于1的数
if((t&(1<<(x))&&!(t&(1<<(y)))) || ((!(t&(1<<(x))))&&(t&(1<<(y)))))
sum+=a[i][j];
}
}
if(sum>maxx) {
maxx=sum;
flag=t;
}
}
for(int i='a'; i<='z'; i++) {
if(flag&(1<<vis2[i])) { // 如果这个字母选了 标记一下
vis[i]=1;
}
}
for(int i=0; i<s.size(); i++) {
if(vis[s[i]]&&(!vis1[s[i]])) { // 标记过了且是辅音字母
cout<<char(s[i]-32);
} else
cout<<s[i];
}
return 0;
}