Codeforces gym 101612 Consonant Fencity (状态压缩+暴力)

Consonant Fencity

时间限制: 3 Sec   内存限制: 512 MB
提交: 100   解决: 15
[ 提交][ 状态][ 讨论版][命题人: admin]

题目描述

There are two kinds of sounds in spoken languages: vowels and consonants. Vowel is a sound, produced with an open vocal tract; and consonant is pronounced in such a way that the breath is at least partly obstructed. For example, letters a and o are used to express vowel sounds, while letters b and p are the consonants (e.g. bad, pot).
Some letters can be used to express both vowel and consonant sounds: for example, y may be used as a vowel (e.g. silly) or as a consonant (e.g. yellow). The letter w, usually used as a consonant (e.g. wet) could produce a vowel after another vowel (e.g. growth) in English, and in some languages (e.g. Welsh) it could be even the only vowel in a word.
In this task, we consider y and w as vowels, so there are seven vowels in English alphabet: a, e, i, o, u, w and y, all other letters are consonants.
Let's define the consonant fencity of a string as the number of pairs of consecutive letters in the string which both are consonants and have different cases (lowercase letter followed by uppercase or vice versa). For example, the consonant fencity of a string CoNsoNaNts is 2, the consonant fencity of a string dEsTrUcTiOn is 3 and the consonant fencity of string StRenGtH is 5.
You will be given a string consisting of lowercase English letters. Your task is to change the case of some letters in such a way that all equal letters will be of the same case (that means, no letter can occur in resulting string as both lowercase and uppercase), and the consonant fencity of resulting string is maximal.

输入

The only line of the input contains non-empty original string consisting of no more than 106 lowercase English letters.

输出

Output the only line: the input string changed to have maximum consonant fencity.

样例输入

consonants

样例输出

coNsoNaNts

题意是给定你一串字符,分为元音字母和辅音字母,将辅音字母变成大写,要构成尽量多的大写字母和小写字母的组合,最后输出改变后的字符串。

由于辅音字母的数量才19个,少到可以状态压缩,将相邻点建边,边权为1,这样可以将字符串转化为1个图,相邻字符的出现次数可以表现为图的权值,这样去枚举每一种状态,然后内层去找每一步状态得到的权值,当权值最大时,保留状态,最后将所有状态为1的点改为大写,输出。

枚举状态的时候,需要判断是否两个辅音字母挨着,如果挨着的话就跳出去,因为这可能是题目说的,一开始读错题意,后来改了改,并没有改这一步,就ok了。也有可能是到现在题意也没读懂。

代码实现:

方案一:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
typedef long long ll;
const int N=1e6+5,mod=1e9+7,INF=0x3f3f3f3f;
int vis_1[300],vis_2[300],a[300][300],vis[1000];
char s[N];

int main()
{
    ll i,j,k;
    scanf("%s",s+1);
    vis_1['a']=vis_1['e']=vis_1['i']=vis_1['o']=vis_1['u']=vis_1['w']=vis_1['y']=1;
    ll t=0;          //num
    for(i='a';i<='z';i++)
        if(!vis_1[i])
        vis_2[i]=t++;
    for(i=1;s[i+1];i++)
    {
        a[s[i]][s[i+1]]++;
    }
    ll maxx=0,flag=0;    //flag--->zhuang tai
    for(t=0;t<(1<<19);t++)
    {
        ll sum=0;
        for(i='a';i<='z';i++)
        {
            if(vis_1[i])
                continue;
            int x=vis_2[i];
            for(j='a';j<='z';j++)
            {
                if(vis_1[j])
                    continue;
                int y=vis_2[j];
                if(((t>>x)&1)!=((t>>y)&1))
                sum+=a[i][j];
            }
        }
        if(sum>maxx)
        {
            maxx=sum;
            flag=t;
        }
    }
//    cout<<flag<<"***"<<endl;
    for(i='a';i<='z';i++)
    {
        if(flag&(1<<vis_2[i]))
            vis[i]=1;
    }
    for(i=1;s[i];i++)
    {
        if(vis[s[i]]&&(!vis_1[s[i]]))
            printf("%c",(char)s[i]-32);
        else
            printf("%c",s[i]);
    }
    puts("");
}

方案二:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5,mod=1e9+7,INF=0x3f3f3f3f;
char f[20]={'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'x', 'z'};
int a[30][30],v[30][30],vis[300];
char s[N];

int main()
{
	int i,j,k;
	scanf("%s",s);
	for(i=0;s[i+1];i++)
	{
		a[s[i]-'a'][s[i+1]-'a']++;
	}
	for(i=0;i<19;i++)
	{
		for(j=0;j<19;j++)
		{
			v[i][j]=a[f[i]-'a'][f[j]-'a'];
		}
	}
	int maxx=0,flag=0;
	for(int t=0;t<(1<<19);t++)
	{
		int sum=0,ss=0;
		for(i=0;i<19;i++)
		{
			for(j=0;j<19;j++)
			{
				if(((t>>i)^(t>>j))&1)
				{
					sum+=v[i][j];
				}
			}
		}
		if(sum>maxx)
		{
			maxx=sum;
			flag=t;
		}
	}
	for(i=0;i<19;i++)
	{
		if(flag&(1<<i))
		{
			vis[f[i]]=1;
		}
	}
	for(i=0;s[i];i++)
	{
		if(vis[s[i]])
		printf("%c",s[i]-32);
		else
		printf("%c",s[i]);
	}
	puts("");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值