Sun Is Me Noip 模拟赛

悄悄话

一、题目及数据范围

点此看题
究极乱搞题
由于凯撒加密的原理非常简单,而且可能的状态区间也就那么26个,所以我们可以枚举出源码。
关键在于判断翻译出来的源码是不是正确的。
语言的特性为我们提供了一种判断方法:英语中有一些高频出现的词汇。所谓“高频出现”是指在绝大多数的英文句子中你都可以找到它们。
于是,我们可以用英文中的常用词建一个词典,诸如 a,I,is,are,… ;然后对于每一个翻译出来的句子,检查里面常用词的数量。常用词的数量越多,就证明它越有可能就是原文。
代码中用权值来代替常用词数量(因为高频字母的数量也会统计,方便累计)。

#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
map<string,bool> mp;
char c,w[10005];
void prepare()
{
        mp["welcome"]=1;
        mp["to"]=1;
        mp["the"]=1;
        mp["test"]=1;
        mp["this"]=1;
        mp["is"]=1;
        mp["the"]=1;
        mp["st"]=1;
        mp["nd"]=1;
        mp["rd"]=1;
        mp["th"]=1;
        mp["last"]=1;
        mp["case"]=1;
        mp["sample"]=1;
        mp["i"]=1;
        mp["im"]=1;
        mp["can"]=1;
        mp["able"]=1;
        mp["happy"]=1;
        mp["sad"]=1;
        mp["my"]=1;
        mp["ender"]=1;
        mp["do"]=1;
        mp["dont"]=1;
        mp["should"]=1;
        mp["didnt"]=1;
        mp["did"]=1;
        mp["are"]=1;
        mp["am"]=1;
        mp["fear"]=1;
        mp["more"]=1;
        mp["and"]=1;
        mp["of"]=1;
        mp["just"]=1;
        mp["have"]=1;
        mp["has"]=1;
        mp["best"]=1;
        mp["worst"]=1;
        mp["robot"]=1;
        mp["how"]=1;
        mp["what"]=1;
        mp["our"]=1;
        mp["his"]=1;
        mp["her"]=1;
        mp["lie"]=1;
        mp["lay"]=1;
        mp["work"]=1;
        mp["in"]=1;
        mp["on"]=1;
        mp["out"]=1;
        mp["scanf"]=1;
        mp["printf"]=1;
        mp["standard"]=1;
        mp["inevitalbe"]=1;
        mp["style"]=1;
        mp["they"]=1;
        mp["by"]=1;
        mp["and"]=1;
        mp["or"]=1;
        mp["that"]=1;
        mp["sing"]=1;
        mp["sleep"]=1;
        mp["when"]=1;
        mp["where"]=1;
        mp["choose"]=1;
        mp["find"]=1;
        mp["care"]=1;
        mp["with"]=1;
        mp["without"]=1;
        mp["cost"]=1;
        mp["cut"]=1;
        mp["count"]=1;
        mp["walk"]=1;
        mp["place"]=1;
        mp["oh"]=1;
        mp["a"]=1;
        mp["an"]=1;
        mp["youre"]=1;
        mp["see"]=1;
        mp["time"]=1;
        mp["no"]=1;
        mp["long"]=1;
        mp["would"]=1;
        mp["peopel"]=1;
        mp["who"]=1;
        mp["night"]=1;
        mp["all"]=1;
        mp["up"]=1;
        mp["come"]=1;
        mp["well"]=1;
        mp["myself"]=1;
        mp["yourself"]=1;
        mp["leave"]=1;
        mp["for"]=1;
        mp["it"]=1;
        mp["here"]=1;
        mp["there"]=1;
        mp["need"]=1;
        mp["some"]=1;
        mp["any"]=1;
        mp["ask"]=1;
        mp["top"]=1;
        mp["at"]=1;
        mp["world"]=1;
        mp["thats"]=1;
        mp["country"]=1;
        mp["hes"]=1;
        mp["too"]=1;
        mp["them"]=1;
        mp["judge"]=1;
        mp["ive"]=1;
        mp["if"]=1;
        mp["but"]=1;
        mp["was"]=1;
        mp["were"]=1;
        mp["a"]=1;
        mp["an"]=1;
        mp["son"]=1;
        mp["them"]=1;
        mp["stop"]=1;
        mp["please"]=1;
        mp["morning"]=1;
        mp["good"]=1;
        mp["bad"]=1;
        mp["thank"]=1;
        mp["end"]=1;
        mp["else"]=1;
        mp["bus"]=1;
        mp["flag"]=1;
        mp["city"]=1;
        mp["lot"]=1;
        mp["many"]=1;
        mp["so"]=1;
        mp["last"]=1;
        mp["late"]=1;
        mp["glad"]=1;
        mp["must"]=1;
        mp["may"]=1;
        mp["could"]=1;
        mp["had"]=1;
        mp["will"]=1;
        mp["shall"]=1;
        mp["try"]=1;
        mp["read"]=1;
        mp["saw"]=1;
        mp["seen"]=1;
        mp["age"]=1;
        mp["zebras"]=1;
}
int main()
{
    prepare();
    for(int i=1;i<=10;i++)
    {
        int sum=0,tot=1,Max=-1,ans;
        string x[10005];
        while(~(c=getchar()) && c!='\n')
        {
            w[++sum]=c;
            if(c==' ' || c==',')
            {
                ++tot;
                continue;
            }
            if(c>='A' && c<='Z')
                c=c-'A'+'a';
            if(c>='a' && c<='z')
                x[tot]+=c;
        }
        for(int k=0;k<26;k++)
        {
            int cnt=0;
            for(int j=1;j<=tot;j++)
            {
                string y;
            	int len=x[j].length();
                for(int l=0;l<len;l++)
                {
                	y+=(x[j][l]-'a'+k)%26+'a';
                }
                if(mp[y])
                    cnt++;
            }
        	if(cnt>Max)
        	{
           		Max=cnt;
          	  	ans=k;
        	}
    	}
        for(int j=1;j<=sum;j++)
        {
        	if(w[j]>='a' && w[j]<='z')
                printf("%c",(w[j]-'a'+ans)%26+'a');
            else if(w[j]>='A' && w[j]<='Z')
                printf("%c",(w[j]-'A'+ans)%26+'A');
            else
                printf("%c",w[j]);
        }
        puts("");
    }
}

细胞自动机

一、题目及数据范围

题目描述
细胞自动制造公司最近刚刚获得批量生产零件的新工艺专利。它的方法使用到包含两种细胞状态的二维网格,每个单元的细胞要么为空,要么为满。当然,具体的细节是专有的。

最初,网格中的一组单元被填充为需要复制的细胞副本。进过一系列离散的步骤,网格中的每个单元会根据自身及附近的八个单元的状态同步进行细胞状态更新。如果这九个单元中有奇数个位置的细胞是满的,那么这个单元的下一个状态也是满的,否则会是空的。

然而,一个 bug 已经蛰伏在工艺中了。在每次更新单元状态之后,网格中某一个单元的状态可能自动变化。其中一个细胞在第一次状态更新后出现了自动变化,另一个细胞在第三次状态更新后出现了自动变化。

很不幸,最初的细胞模式丢失了,只有(可能受到 bugbugbug 影响的) 复制结果保留了下来。你能否编个程序确定可能的最小的非空的初始细胞模式来产生给定的最终模式呢?

输入描述
第一行包含两个整数 www ( 1≤w≤300 )和 hhh ( 1≤h≤300 ),其中 w 和 h 表示最终模式的边框宽度与高度。接下来 h 行,每行包含 w 个字符,描述了最终的模式。每个字符要么是’.’(表示该单元为空),要么是’#’(表示该单元为满) 。保证在第一行、最后一行、第一列、最后一列均存在至少一个单元是满的。

输出描述
输出最小的非空的可能产生最终模式的初始模式,这里假设每个阶段至多会有一个单元状态自动变化。模式的大小取决于边框内的区域。如果由多种可能的最小的非空的初始模式,那么任意一种答案都是可接受的。请你使用字符’.‘表示空的单元,使用’#'表示满的单元。请你用必须要使用的最小行数和列数来输出这个模式。

二、解法

每次更新一格后,细胞都会自动扩展一格,所以更新次数是 O ( n ) O(n) O(n)的。
同时,根据题意,我们能列出下列表达式:
y i , j = x i , j ⊕ x i − 1 , j ⊕ x i + 1 , j ⊕ x i , j − 1 ⊕ x i , j + 1 ⊕ x i − 1 , j + 1 ⊕ x i − 1 , j − 1 ⊕ x i + 1 , j − 1 ⊕ x i + 1 , j + 1 y_{i,j}=x_{i,j}\oplus x_{i-1,j}\oplus x_{i+1,j}\oplus x_{i,j-1}\oplus x_{i,j+1}\oplus x_{i-1,j+1}\oplus x_{i-1,j-1}\oplus x_{i+1,j-1}\oplus x_{i+1,j+1} yi,j=xi,jxi1,jxi+1,jxi,j1xi,j+1xi1,j+1xi1,j1xi+1,j1xi+1,j+1
⇒ y i , j ⊕ x i − 1 , j − 1 = x i , j ⊕ x i − 1 , j ⊕ x i + 1 , j ⊕ x i , j − 1 ⊕ x i , j + 1 ⊕ x i − 1 , j + 1 ⊕ x i + 1 , j − 1 ⊕ x i + 1 , j + 1 \Rightarrow y_{i,j}\oplus x_{i-1,j-1}=x_{i,j}\oplus x_{i-1,j}\oplus x_{i+1,j}\oplus x_{i,j-1}\oplus x_{i,j+1}\oplus x_{i-1,j+1}\oplus x_{i+1,j-1}\oplus x_{i+1,j+1} yi,jxi1,j1=xi,jxi1,jxi+1,jxi,j1xi,j+1xi1,j+1xi+1,j1xi+1,j+1
⇒ x i − 1 , j − 1 = x i , j ⊕ x i − 1 , j ⊕ x i + 1 , j ⊕ x i , j − 1 ⊕ x i , j + 1 ⊕ x i − 1 , j + 1 ⊕ x i + 1 , j − 1 ⊕ x i + 1 , j + 1 ⊕ y i , j \Rightarrow x_{i-1,j-1}=x_{i,j}\oplus x_{i-1,j}\oplus x_{i+1,j}\oplus x_{i,j-1}\oplus x_{i,j+1}\oplus x_{i-1,j+1}\oplus x_{i+1,j-1}\oplus x_{i+1,j+1}\oplus y_{i,j} xi1,j1=xi,jxi1,jxi+1,jxi,j1xi,j+1xi1,j+1xi+1,j1xi+1,j+1yi,j

有了这个式子,我们就可以从左上到右下来更新,我们考虑如果一个bug在 ( i , j ) (i,j) (i,j),它的影响。

( i , j ) (i,j) (i,j)出现 Bug 的时候, ( i + 1 , j ) , ( i + 1 , j + 1 ) , . . . , ( i + 1 , j + 3 k ) , ( i + 1 , j + 3 k + 1 ) (i+1,j),(i+1,j+1),...,(i+1,j+3k),(i+1,j+3k+1) (i+1,j),(i+1,j+1),...,(i+1,j+3k),(i+1,j+3k+1)都会被改变。
而我们知道,在无 Bug情况下, ( i , w + 1 ) (i,w+1) (i,w+1) ( i , w + 2 ) (i,w+2) (i,w+2)都是无细胞的。现在出了Bug,那么 ( i , w + 1 ) (i,w+1) (i,w+1) ( i , w + 2 ) (i,w+2) (i,w+2)中有一个必会出现“细胞”。这样即可判断Bug所在的行。
接下来把培养皿翻转一波,再按照上面的方法跑一遍,就可以得到Bug所在的列。修复Bug之后继续推。

最后一个问题:怎么判断当前是否最简?
假如当前推出来的行数或者列数只有1,就必然是最优的。否则,如果当前出现“除掉一个Bug,还有一个Bug的情况“,也算是最简情况。

#include <cstdio>
const int MAXN = 305;
int read()
{
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*flag;
}
int ex,ey,sx,sy,px[MAXN],py[MAXN];
int cnt,Y[MAXN][MAXN],X[MAXN][MAXN],ans[MAXN][MAXN];
char str[MAXN];
void upd()
{
	for(int i=sx;i<=ex;i++)
		for(int j=sy;j<=ey;j++)
			ans[i-sx][j-sy]=Y[i][j];
}
int get_row()
{
	for(int i=sx;i<=ex+1;i++)
	{
		for(int j=sy;j<=ey+2;j++)
			X[i][j]=Y[i-1][j-1]^X[i-2][j-2]^X[i-2][j-1]^X[i-2][j]^
			X[i-1][j-2]^X[i-1][j-1]^X[i-1][j]^X[i][j-2]^X[i][j-1];
		if(X[i][ey+1]+X[i][ey+2]>0) return i-1;
	}
	return 0;
}
int get_col()
{
	for(int j=sy;j<=ey+1;j++)
	{
		for(int i=sx;i<=ex+2;i++)
			X[i][j]=Y[i-1][j-1]^X[i-2][j-2]^X[i-2][j-1]^X[i-2][j]^
			X[i-1][j-2]^X[i-1][j-1]^X[i-1][j]^X[i][j-2]^X[i][j-1];
		if(X[ex+1][j]+X[ex+2][j]>0) return j-1;
	}
	return 0;
}
void del()
{
	for(;sx<ex;sx++)
	{
		int ok=0;
		for(int j=sy;j<=ey;j++) ok+=X[sx][j];
		if(ok) break;
	}
	for(;sx<ex;ex--)
	{
		int ok=0;
		for(int j=sy;j<=ey;j++) ok+=X[ex][j];
		if(ok) break;
	}
	for(;sy<ey;sy++)
	{
		int ok=0;
		for(int i=sx;i<=ex;i++) ok+=X[i][sy];
		if(ok) break;
	}
	for(;sy<ey;ey--)
	{
		int ok=0;
		for(int i=sx;i<=ex;i++) ok+=X[i][ey];
		if(ok) break;
	}
}
void copy()
{
	for(int i=sx;i<=ex;i++)
		for(int j=sy;j<=ey;j++)
			Y[i][j]=X[i][j];
}
int main()
{
	sx=sy=2;
	ey=read()+1;ex=read()+1;
	for(int i=sx;i<=ex;i++)
	{
		scanf("%s",str+sy);
		for(int j=sy;j<=ey;j++)
			if(str[j]=='#')
				Y[i][j]=1;
	}
	for(upd();sx+1<ex && sy+1<ey;upd())
	{
		cnt++;
		int x=get_row();
		if(x)
		{
			int y=get_col();
			px[cnt]=x;py[cnt]=y;
			Y[x][y]^=1;
			if(get_row())
			{
				cnt--;
				break;
			}
		}
		copy(),del();
	}
	for(int i=0;i<=ex-sx;i++,puts(""))
		for(int j=0;j<=ey-sy;j++)
			printf("%c",ans[i][j]?'#':'.');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值