enc
【问题背景】
zhx 和他的妹子聊天。
【问题描述】
考虑一种简单的加密算法。
假定所有句子都由小写英文字母构成,对于每一个字母,我们将它唯一地映
射到另一个字母。例如考虑映射规则:
a->b, b->c, c->d, d->a. 那么单词 bad 就会被映射为 cba。这个映射规则的“逆
映射规则”为: b->a, c->b, d->c, a->d。 对于密文 cba, 我们很容易将它解密为 bad。
当然,这样的映射需要保证每一个字母映射到的字母是不同的(即不可以出
现两个不同的字母映射到同一个字母,否则将会无法解密) 。
一种常见的密码攻击方式被称为已知明文攻击。具体地,在你不知道映射表
的情况下,给你一段明文和对应的密文,你可以推导出一些的映射规则,下一次
你收到一条密文,你就可能可以解密它。现在你需要完成这样的一个系统。
【输入格式】
第一行包含一个字符串,仅包含小写字母,表示一段明文。
第二行包含一个字符串,仅包含小写字母,表示这段明文对应的密文,保证
两行长度相同。
第三行包含一个字符串,仅包含小写字母,表示你需要解密的密文。
【输出格式】
输出共一行,表示输入中第三行密文对应的明文。如果不能解密,输出
“ERROR”(不包含引号) 。注意输入可能出现不自恰的情况。
【样例输入】
ab
cc
cc
【样例输出】
ERROR
【样例输入】
ab
ab
c
【样例输出】
ERROR
【样例输入】
abcde
bcdea
cad
【样例输出】
bec
【数据范围与规定】
对于100%的数据,所有字符串长度<=1000。

/*模拟 有特殊情况没想到 如果25个都已经对应好了 剩下的即使不出现也能对应了 90*/
#include<cstdio>
#include<cstring>
#define maxn 1010
using namespace std;
int n,len,f[],g[],falg,c1,c2,A,B;
char s[maxn],s1[maxn],s2[maxn];
int main()
{
freopen("enc.in","r",stdin);
freopen("enc.out","w",stdout);
scanf("%s%s%s",s1,s2,s);
n=strlen(s1);len=strlen(s);
for(int i=;i<n;i++){
if(g[s1[i]]&&g[s1[i]]!=s2[i]){
falg=;break;
}
if(f[s2[i]]&&f[s2[i]]!=s1[i]){
falg=;break;
}
if(f[s2[i]]==)f[s2[i]]=s1[i],c1++;
if(g[s1[i]]==)g[s1[i]]=s2[i],c2++;
}
if(c1==&&c2==){
for(int i='a';i<='z';i++)
if(f[i]==)A=i;
for(int i='a';i<='z';i++)
if(g[i]==)B=i;
f[A]=B;
}
for(int i=;i<len;i++)
if(f[s[i]]==){
falg=;break;
} if(falg){
printf("ERROR\n");return ;
}
for(int i=;i<len;i++)
printf("%c",f[s[i]]);
return ;
}


【问题背景】
zhx 给他的妹子们排序。
【问题描述】
zhx 有 N 个妹子,他对第 i 个妹子的好感度为? ? , 且所有? ? ,两两不相等。现
在 N 个妹子随意站成一排,他要将她们根据好感度从小到大排序。他使用的是
冒泡排序算法(详见下) 。如果排序过程中好感度为? ? 的妹子和好感度为? ? 的妹
子发生了交换,那么她们之间会发生一场口角。
现在 zhx 想知道,给定妹子的初始排列,在排序完成后,最多存在多少个妹
子,她们任意两人之间没发生过口角。
正式地,考虑对数组? ? 进行冒泡排序,如果? ? 和? ? 在排序过程中发生交换,
那么在两个元素之间连一条边。 你需要求出, 排序结束后, 最多存在多少个元素,
其中任意两个元素之间不存在连边。冒牌排序算法如下:
【输入格式】
第一行两个整数 N,表示妹子数量。
接下来一行 N 个整数? ? ,表示初始第 i 个妹子的好感度。
【输出格式】
一行一个整数,表示最多满足要求的妹子的个数。
【样例输入】
3
3 1 2
【样例输出】
2
【样例解释】
{1, 2}。
【数据规模与约定】
316。
70%的数据,1 ≤ ? ≤ 50。
对于100%的数据,1 ≤ ? ≤ 100000, 0 ≤ ? ? < ?。

/*手打个冒泡 把swap的输出出来不难发现就是求LIS*/
#include<cstdio>
#include<algorithm>
#define maxn 100010
using namespace std;
int n,x,c[maxn],num;
int init(){
int x=,f=;char s=getchar();
while(s<''||s>''){if(s=='-')f=-;s=getchar();}
while(s>=''&&s<=''){x=x*+s-'';s=getchar();}
return x*f;
}
int main()
{
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
n=init();c[]=-0x7fffffff;
for(int i=;i<=n;i++){
x=init();
if(x>c[num]){
c[++num]=x;continue;
}
int pos=lower_bound(c+,c++num,x)-c;
c[pos]=x;
}
printf("%d\n",num);
return ;
}


【问题背景】
zhx 和他的妹子(们)做游戏。
【问题描述】
考虑 N 个人玩一个游戏, 任意两个人之间进行一场游戏 (共 N*(N-1)/2 场) ,
且每场一定能分出胜负。
现在,你需要在其中找到三个人构成“剪刀石头步”局面:三个人 A,B,C
满足 A 战胜 B,B 战胜 C,C 战胜 A。
【输入格式】
第一行一个正整数 N,表示参加游戏的人数。
接下来 N 行,每行 N 个数 0/1,中间没有空格隔开。第 i 行第 j 列数字为 1
表示 i 在游戏中战胜了 j。所有对角线元素(即第 i 行第 i 个元素)为 0,保证数
据合法。
【输出格式】
如果存在三个人构成“剪刀石头布”局面,输出三个人的编号(从 1 开始) 。
如果不存在这样的三个人,输出一个数-1。
【样例输入】
5
00100
10000
01001
11101
11000
【样例输出】
1 3 2
【数据规模与约定】
55。
80%的数据,1 ≤ ? ≤ 10。
对于100%的数据,1 ≤ ? ≤ 5000

/*暴力枚举三个点是谁 应该可以80 */
#include<cstdio>
#include<ctime>
#define maxn 5010
using namespace std;
int n,num,head[maxn],ans[maxn][],f[maxn],falg;
struct node{
int v,pre;
}e[maxn*maxn];
char s[maxn][maxn];
void Add(int from,int to){
num++;e[num].v=to;
e[num].pre=head[from];
head[from]=num;
}
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",s[i]+);
for(int j=;j<=n;j++)
if(s[i][j]=='')Add(i,j);
}
for(int x=;x<=n;x++){
for(int i=head[x];i;i=e[i].pre){
int y=e[i].v;
for(int j=head[y];j;j=e[j].pre){
int z=e[j].v;
if(s[z][x]==''){
if(f[x]==){
f[x]=;ans[x][]=y;ans[x][]=z;
}
else if(ans[x][]>y){
ans[x][]=y;ans[x][]=z;
}
else if(ans[x][]==y&&ans[x][]>z)
ans[x][]=z;
}
}
}
if(f[x]){
printf("%d %d %d\n",x,ans[x][],ans[x][]);
falg=;break;
}
}
if(!falg)printf("-1\n");
return ;
}
/*
这题真是够了 题目没说清楚
special judge 还没发用
自己打了80分的 应该是没啥问题
然而超时
虽然到最后改成了20 2333
但是自己测试的答案是没问题的
有个spj就好了
说说正解的思想吧
很巧妙地降低了复杂度
首先找环 找到的第一个>=3的环
(其实不会存在2的)
就停下 答案一定在这里面的三个
为什么呢
首先要是环大小为3 这没啥问题
关键是>3的 为什么一定存在合法的 合法的怎么找
这就有套路了
可以自己画个环 因为保证每两人之间都有边
那么无论怎么加边 一定会构成一个三元环
自己动手画画吧 应该很容易看出来 (就是想不到23333)
照这样的的话 那一定有两个是挨着的
但如果枚举两个的话就很慢了
我们只枚举一个 并且把一个固定在起点
我们把起点作为x 枚举的这个作为y 他后面的这个作为z
那么 y->z 一定有边 然后我们加判断 保证 z->x有边
现在就剩下一条了就是x->y的这条 如果这条也确定的话 就构成环了
我们放慢这个枚举的过程来看的话
第一次 x=1 y=2 z=3 这时可以保证 x->y 有边
如果z->x 有边的话 就找到了 停下
如果没有z->x的边 根据两两必有输赢的题意
那一定是x->z 有边
然后我们到下一层 那就保证了x->y 有边了
后面一样的 这里画图脑补一下吧
这样就好了
*/
#include<cstdio>
#include<stack>
#include<vector>
#define maxn 5010
using namespace std;
int n,num,head[maxn],dfn[maxn],low[maxn],f[maxn],falg,top,topt,sum,c[maxn];
stack<int>S;
vector<int>G[maxn];
struct node{
int v,pre;
}e[maxn*maxn];
char s[maxn][maxn];
void Add(int from,int to){
num++;e[num].v=to;
e[num].pre=head[from];
head[from]=num;
}
void Tarjan(int u){
dfn[u]=low[u]=++topt;
f[u]=;S.push(u);
for(int i=head[u];i;i=e[i].pre){
int v=e[i].v;
if(dfn[v]==){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(f[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
while(u!=S.top()){
c[++c[]]=S.top();f[S.top()]=;S.pop();
}
c[++c[]]=S.top();f[S.top()]=;S.pop();
if(c[]<)c[]=;
else {
sum++;falg=;
for(int i=c[];i>=;i--)
G[sum].push_back(c[i]);
}
}
}
void Printf(){
for(int k=;k<=sum;k++)
if(G[k].size()>=){
int x,y,z;x=G[k][];
for(int i=;i<G[k].size()-;i++){
y=G[k][i];z=G[k][i+];
if(s[z][x]==''){
printf("%d %d %d\n",x,y,z);break;
}
}
break;
}
}
int main()
{
freopen("game.in","r",stdin);
freopen("game.ans","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",s[i]+);
for(int j=;j<=n;j++)
if(s[i][j]=='')Add(i,j);
}
for(int i=;i<=n;i++){
if(dfn[i]==)Tarjan(i);
if(falg){
Printf();break;
}
}
if(!falg)printf("-1\n");
return ;
}
04-27 03:26