1. 成语纠错
问题背景
你的任务是给一个错误的四字成语进行纠错,找到它的正确写法。具体来说,你只允许修改四个汉字中的其中一个,使得修改后的成语在给定的成语列表中出现。原先的错误成语保证不在成语列表中出现。
有时,这样的“纠错”结果并不惟一。例如“一糯千金”可以改为“一字千金”也可以改成“一诺千金”。但由于“糯”和“诺”是同音字,“一糯千金”实为“一诺千金”的可能性比较大。
因此,我们还将提供一个汉字分类表,要求修改前后的两个字必须属于同一个分类。
在这样的限制下,我们保证成语纠错的结果惟一。
注意
1、汉字均采用GBK编码(参见FAQ)
2、每个汉字分类至少包含两个汉字,同一个汉字可能出现在多个类别中。
3、成语列表中的成语都是真实存在的四字成语。成语列表和待纠错成语中的所有汉字均在汉字分类表中的至少一个分类中出现。
输入格式
输入第一行包含两个整数n,m(1<=n<=200,1<=m<=20000)。n表示汉字类别的个数,m表示成语的个数。
以下n行每行用一个无空白分隔符(空格、TAB)的汉字串表示一个分类中的所有汉字。注意,该汉字串最多可能包含200个汉字。
以下m行为成语列表,每行一个成语,恰好四个汉字。
最后一行为待纠错的成语,恰好四个汉字,且不在成语列表中出现。
输出格式
仅一行,为一个四字成语。在“修改必须在同一分类中进行”的限制下,输入数据保证纠错结果惟一。
样例输入
7 3
糯诺挪喏懦
字自子紫籽
前钱千牵浅
进近今仅紧金斤尽劲
完万
水睡税
山闪衫善扇杉
一诺千金
一字千金
万水千山
一糯千金
样例输出
一诺千金
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
*
* @author phinecos
* @since 2009-05-22
*
*/
public class Test
{
private static List < String > catelogs = new ArrayList < String > ();
private static List < String > phrases = new ArrayList < String > ();
public static int isValidPhrase(String strTested,String strBase)
{ // 判断此成语是否与基准字符串只差一个字,若是,则返回此索引,否则返回-1
int i,count = 0 ,pos = - 1 ;
for (i = 0 ; i < strBase.length(); ++ i)
{
if (strBase.charAt(i) != strTested.charAt(i))
{
++ count;
pos = i;
}
}
if (count == 1 )
{ // 仅一字之差
return pos;
}
else
{
return - 1 ;
}
}
public static boolean isSameCatelog( char chTested, char chBase)
{ // 测试两个汉字是否在同一个类别下
for (String catelog : catelogs)
{
if ((catelog.indexOf(chBase) != - 1 ) && (catelog.indexOf(chTested) != - 1 ))
{ // 两个汉字在同一个类别下
return true ;
}
}
return false ;
}
public static String correctPhrase(String wrongPhrase)
{ // 纠正错误
int pos;
Iterator < String > iter = phrases.iterator();
char chBase,chTested;
String result = "" ;
while (iter.hasNext())
{
String phrase = iter.next(); // 取成语表中当前成语
pos = isValidPhrase(wrongPhrase, phrase);
if ( pos != - 1 )
{ // 与成语表中当前成语仅一字之差
chBase = phrase.charAt(pos);
chTested = wrongPhrase.charAt(pos);
if (isSameCatelog(chTested, chBase) == true )
{ // 在同一个类别下,可以进行修改
StringBuilder sb = new StringBuilder(wrongPhrase);
sb.setCharAt(pos, chBase);
result = sb.toString();
break ;
}
}
}
return result;
}
public static void main(String[] args) throws IOException
{
int n,m,i;
java.util.Scanner scanner = new java.util.Scanner(System.in);
// 读入n,m,(1<=n<=200,1<=m<=20000)。n表示汉字类别的个数,m表示成语的个数。
n = scanner.nextInt();
m = scanner.nextInt();
// 汉字分类表,每个分类中最多包含200个汉字
for (i = 0 ; i < n; ++ i)
{
catelogs.add(scanner.next());
}
// 成语列表
for (i = 0 ; i < m; ++ i)
{
phrases.add(scanner.next());
}
// 输入待纠错成语
String wrongPhrase = scanner.next();
// 输出纠错后成语
System.out.println(correctPhrase(wrongPhrase));
}
}
2,公平数
问题背景
如果一个整数的十六进制表示(不含前导0)中,前一半数字之和等于后一半数字之和,我们称它为公平数。
注意,如果该数的十六进制表示中包含奇数个数字,则正中间的数字既不属于前一半,又不属于后一半。
例如在十六进制下1+D=7+7,因此1DE77是公平数。数字E并不参与计算。
再例如,所有单个数字的十六进制数(即0~F)均为公平数,但F0不是(不能把F0补充前导0写成0F0,进而认为它是公平数)。
给出十六进制数 K, X, Y 和十六进制数字集合 S,求区间[X, Y]之内,有多少个公平数满足:
十六进制表达式(不包含前导0)中每个数字均在集合S中
并且为K的倍数
输入格式
输入第一行为数字集S,包含0~9以及大写字母A~F。
每个数字或字母最多出现一次。
第二行包含 3 个十六进制正整数K, X, Y,均不超过 10 个数字(包含0~9以及大写字母A~F,不包含前导 0)。
输出格式
仅一行,包含一个整数,即满足条件的公平数个数(10进制)。
样例输入
124C
5 100 FFF
样例输出
4
样例解释
只有四个数满足条件:212,424,4C4,C1C。
/* Author: phinecos Date:2009-05-22 */
/* ********************************************************************** */
#include < iostream >
using namespace std;
char s[ 17 ] = { 0 }; // 十六进制数字集合S
long k,x,y; // 十六进制数X,Y,K
void charupper( char * string )
{
int i;
for (i = 0 ;i < strlen( string );i ++ )
{
if ( string [i] >= ' a ' && string [i] <= ' z ' )
string [i] -= ' a ' - ' A ' ;
}
}
bool checksinglechar( char ch)
{
int i;
for (i = 0 ;i < strlen(s);i ++ )
if (s[i] == ch)
return true ;
return false ;
}
bool isAllInSet( long num)
{
char tstring[ 12 ];
int i;
sprintf(tstring, " %lx " ,num);
charupper(tstring);
for (i = 0 ;i < strlen(tstring);i ++ )
{
if (checksinglechar(tstring[i]) == false )
return false ;
}
return true ;
}
int convert( char ch)
{
if (ch >= ' a ' && ch <= ' f ' )
{
return (ch - ' a ' + 10 );
}
else if (ch >= ' A ' && ch <= ' F ' )
{
return (ch - ' A ' + 10 );
}
else if (ch >= ' 0 ' && ch <= ' 9 ' )
{
return (ch - ' 0 ' );
}
else
return 0 ;
}
bool isFairNum( long num)
{ // 检查是否是公平数
char tstring[ 100 ] = { 0 };
int bsum = 0 ,lsum = 0 ;
int i;
ltoa(num,tstring, 16 ); // 转换为进制
if (strlen(tstring) % 2 == 0 )
{ // 若长度为偶数,比较前一半数字之和与后一半数字之和
for (i = 0 ;i < strlen(tstring) / 2 ;i ++ )
bsum += convert(tstring[i]);
for (i = strlen(tstring) / 2 ;i < strlen(tstring);i ++ )
lsum += convert(tstring[i]);
if (bsum == lsum)
{
return true ; // 是公平数
}
else
{
return false ;
}
}
else
{ // 若长度为奇数,忽略掉中间的数字
for (i = 0 ;i < strlen(tstring) / 2 ;i ++ )
bsum += convert(tstring[i]);
for (i = strlen(tstring) / 2 + 1 ;i < strlen(tstring);i ++ )
lsum += convert(tstring[i]);
if (bsum == lsum)
{
return true ; // 是公平数
}
else
{
return false ;
}
}
}
int main()
{
cin >> s;
cin >> hex >> k >> x >> y;
long nCount = 0 ; // 符合条件的数字个数
for ( long num = x; num <= y; ++ num)
{
if ((num % k) == 0 )
{ // 是k的倍数
if (isFairNum(num) == true )
{ // 是公平数
if (isAllInSet(num) == true )
{ // 检查十六进制表达式(不包含前导)中每个数字是否均在集合S中
++ nCount;
}
}
}
}
cout << nCount << endl;
return 0 ;
}