[BZOJ2145]悄悄话

题意:给出用凯撒加密法加密后的密文,求原文。

这道题让我想起了三年前做的唐教出那个提交答案题,那道题的加密是一个全排列,破解起来非常困难,当时和lzm他们一群人在机房开黑搞这题搞了一整场考试的时间,得了60分23333

这个题凯撒加密的方法只有26种,可以枚举判断。

其实APIO上讲课时提到过这个题的。但是我看了题目后发现他保证句子长度大于等于3,又没有保证是从哪里截取的自然英文还是出题人刻意造的刁钻句子,所以显然不能直接统计字母频率。。

最好的方法是从单词下手。我差不多用了一个小时想了一些常见单词还有词缀,然后乱搞了些参数。后来搞到数据测了一下,发现只有10分。。本来设置了一个子串识别功能,就是一个单词的子串出现在单词表中时也要加分,并且长度越大加的分越大,后来发现一个被错误解密的单词中竟然完整地包含了一个"there"我了个大擦!于是我(面向数据)加了个限制就是子串重合的话必须要超过5个字母23333

后来调了很久发现始终只能得60分左右,就又去查看了一波数据,发现有一个句子其中一大半的单词都在我的单词表中但是没翻译对,然后我发现我提取出来单词后没封斜杠0,相当于我之前写的单词识别部分只有第一个单词识别对了!汗这也能过60。。。加上个memset之后终于A了。。。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<map>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef unsigned long long u64;

char buf[10000], s[10000], word[10000], d[10000], ss[10000];
bool yuan[26];
map<u64, int> ha;

char dict[1000][30] = {
"am","is","are","was","were","been",
"a","an","the","this","that","these","those","there","even",
"i","me","my","you","your","he","his","him","she","her","hers","we","our","ours","it","its",
"up","to","for","in","out","of","on","above","below","over","under","into","after","before",
"what","where","when","how","why","if","then","else","begin","end","while","break","continue",
"yes","no","never","ever","sure","thank","thanks","welcome","sorry","and","or","but","though","although",
"morning","afternoon","evening","nignt","please","file"
};

char noun[1000][30] = {
"tom","bob","alice","david","james","peter","tony","friend","wife","husband","aunt","uncle",
"book","desk","table","computer","bed","pen","man","woman","women","men","boy","girl","people","time","kid","child",
"cat","dog","cow","pig","mouse","mice","rice","one","two","three","four","five","six","seven","eight","nine","ten",
"son","daughter","shower","rain","weather","sun","sunny","wind","snow","fire","water","river","sea",
"window","floor","house","room","door","way","road","street","light","word",
"car","bike","bus","truck","plane","air","king","queen","sodier",
"dollars","money","cake","bread","math","chinese","english","hand","eye","head","body","mouth",
"apple","banana","orange","pear","tree","grass","melon","bush",
"city","country","nation","flag","breakfast","lunch","dinner"
};

char ad[1000][30] = {
"good","well","bad","nice","beautiful","better","worse","happy","glad","sad","other","recent"
"green","white","yellow","blue","red","purple","big","large","small","again","just",
"lot","lots","some","many","so","first","second","last","early","late","sweet","new","old","young"
};

char verb[1000][30] = {
"must","might","should","can","could","may",
"do","did","play","like","want","love","go","went","gone","say","said","sais","test","make","get","getting","got",
"have","has","had","will","shall","use","try","read","write","see","saw","seen","look","smell","smelt","hear","heard",
"exciting","intersting","came","find","found","wash","clean","sleep","eat","drink","take","took","taken","fly","cook"
"give","gave","given","hide","hid","hidden","swim","swam","run","walk","walked","pay","paid"
};

char suffix[1000][30] = {
"s","es","ing","ed","ies","ly","ty","teen","er","ers","tant","tent","ists","ve",
"ever","room","ious","ish","tion","age","ache","ster","ant","nal","tal","cal","sal","ple"
};

char prefix[1000][30] = {
"dis","des","pre","in","im","un","anti","sub","con","com","under","over","ex",
"re","ist","ists","en","trans","bi","mono","tri","octo","inter","ele","tele"
};

bool rec_upper[10000];
int val[30];

int trans(char c, int v)
{
	if (!isalpha(c)) return c;
	int a = c;
	if (islower(c)) { a += v; if (a>'z') a-=26; }
	else { a += v; if (a>'Z') a-=26; }
	return a;
}

int sum[26], bd[26];
void deal_word(int len, int totwd)
{
	memset(d,0,sizeof d);
	for (int x = 0; x<26; ++x)
	{
		int xflag = 0;
		for (int i = 0; i<len; ++i) d[i] = trans(word[i], x);
		if (rec_upper[0] && len==1 && d[0]!='i') { val[x]-=99999; continue; } 
		for (int i = 0; dict[i][0]; ++i)
			if (strcmp(dict[i], d)==0)
			{
				if (len==1) val[x] += 5;
				else if (len>5) val[x] += 99999;
				else if (len>=5) val[x] += len*len*len*15;
				else val[x] += len*20;
				sum[x]++;
			}
		for (int i = 0; ad[i][0]; ++i)
			if (strcmp(ad[i], d)==0)
			{
				if (len==1) val[x] += 5;
				else if (len>5) val[x] += 99999;
				else if (len>=5) val[x] += len*len*len*15;
				else val[x] += len*20;
				sum[x]++;
			}
		for (int i = 0; noun[i][0]; ++i)
			if (strcmp(noun[i], d)==0)
			{
				if (len==1) val[x] += 5;
				else if (len>5) val[x] += 99999;
				else if (len>=5) val[x] += len*len*len*15;
				else val[x] += len*20;
				sum[x]++;
			}
		for (int i = 0; verb[i][0]; ++i)
			if (strcmp(verb[i], d)==0)
			{
				if (len==1) val[x] += 5;
				else if (len>5) val[x] += 99999;
				else if (len>=5) val[x] += len*len*len*15;
				else val[x] += len*20;
				sum[x]++;
			}
		for (int i = 0; prefix[i][0]; ++i)
		{
			bool flag = 1;
			for (int j = 0; prefix[i][j]; ++j) if (d[j]!=prefix[i][j]){flag=0;break;}
			if (flag) val[x] += strlen(prefix[i])*strlen(prefix[i])*strlen(prefix[i])*6;
		}
		for (int i = 1, t; suffix[i][0]; --i)
		{
			bool flag = 1; t=strlen(suffix[i]);
			for (int j = 0; j<len&&j<t&&t<=len; ++j) if (d[len-i-1]!=suffix[i][t-j-1]) {flag=0;break;}
			if (flag) val[x] += t*t*t*6;
		}
		for (int i = 0; d[i]; ++i)
		{
			u64 h = 0;
			for (int j = i, k; d[j]; ++j)
			{
				h = h*31+d[j]-'a'+1;
				if ((k=ha[h])>4) val[x] += k*k*k*8;
			}
		}
		for (int i = 0; d[i]&&d[i+1]; ++i)
		{
			if (rec_upper[i]) continue;
			if (yuan[d[i]-'a']^yuan[d[i+1]-'a'])
				val[x] ++;
			if (d[i+2] && yuan[d[i]-'a']==yuan[d[i+1]-'a']&&yuan[d[i]-'a']==yuan[d[i+2]-'a'])
			{
				if(d[i]=='g'&&d[i+1]=='h'&&d[i+2]=='t')continue;
				if (yuan[d[i]-'a']) bd[x]+=2;
				else bd[x]++;
				if (bd[x]>=5) val[x] -= 99999;
			}
		}
	}
}

void deal_string(int len, int xn)
{
	bool flag = 0;
	for (int i = 0; i<len; ++i)
		if (isalpha(s[i])) flag = 1;
	if (!flag) return;
	int t = 0;
	for (int i = 0; i<=len; ++i)
	{
		if (!isalpha(s[i])) word[t]='\0', deal_word(t, xn), t = 0, memset(word,0,sizeof word);
		else {
			if (isupper(s[i])) word[t] = tolower(s[i]), rec_upper[t] = 1, t++;
			else word[t] = s[i], rec_upper[t] = 0, t++;
		}
	}
}

void solve()
{
	memset(buf, 0, sizeof buf);
	memset(s, 0, sizeof s);
	memset(sum,0,sizeof sum);
	memset(bd, 0, sizeof bd);
	gets(buf);
	memset(val, 0, sizeof val);
	int i = 0, j = 0, len = strlen(buf), xn = 1;
	for (i = 0; i<len; ++i) if(buf[i]==' ') xn++;
	for (i = j = 0; i<len; i+=j)
	{
		while ((buf[i]==' '||buf[i]=='\n'||buf[i]=='\t'||buf[i]=='\r')&&i<len) ++i;
		for (j = 0; buf[i+j]!=' '&&buf[i+j]!='\n'&&buf[i+j]!='\r'&&buf[i+j]!='\t'&&buf[i+j]; j++) s[j] = buf[i+j];
		deal_string(j, xn); memset(s, 0, sizeof s);
	}
	for (int i = 0; i<26; ++i) if (xn>=10?(sum[i]>=xn/3):(sum[i]>=xn/2)) val[i]+=1234;
	int opt = 0;
	for (int i = 1; i<26; ++i) if(val[i]>val[opt]) opt = i;
	for (i = 0; i<len; ++i) if (isalpha(buf[i])) putchar(trans(buf[i], opt)); else putchar(buf[i]);
	puts("");
}

void GlobalHash()
{
	for (int i = 0; dict[i][0]; ++i)
	{
		u64 h = 0;
		if (strlen(dict[i])<3) continue;
		for (int j = 0; dict[i][j]; ++j) h = h*31+dict[i][j]-'a'+1;
		ha[h] = strlen(dict[i]);
	}
	for (int i = 0; noun[i][0]; ++i)
	{
		u64 h = 0;
		if (strlen(noun[i])<3) continue;
		for (int j = 0; noun[i][j]; ++j) h = h*31+noun[i][j]-'a'+1;
		ha[h] = strlen(noun[i]);
	}
	for (int i = 0; verb[i][0]; ++i)
	{
		u64 h = 0;
		if (strlen(verb[i])<3) continue;
		for (int j = 0; verb[i][j]; ++j) h = h*31+verb[i][j]-'a'+1;
		ha[h] = strlen(verb[i]);
	}
	for (int i = 0; ad[i][0]; ++i)
	{
		u64 h = 0;
		if (strlen(ad[i])<3) continue;
		for (int j = 0; ad[i][j]; ++j) h = h*31+ad[i][j]-'a'+1;
		ha[h] = strlen(ad[i]);
	}
}

int main()
{
	freopen("msg.in", "r", stdin);
	freopen("msg.out", "w", stdout);
	yuan[0]=yuan['e'-'a']=yuan['i'-'a']=yuan['o'-'a']=yuan['u'-'a']=1;
	GlobalHash();
	rep(i, 1, 10)
		solve();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值