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[210],g[210],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=0;i<n;i++){ if(g[s1[i]]&&g[s1[i]]!=s2[i]){ falg=1;break; } if(f[s2[i]]&&f[s2[i]]!=s1[i]){ falg=1;break; } if(f[s2[i]]==0)f[s2[i]]=s1[i],c1++; if(g[s1[i]]==0)g[s1[i]]=s2[i],c2++; } if(c1==25&&c2==25){ for(int i='a';i<='z';i++) if(f[i]==0)A=i; for(int i='a';i<='z';i++) if(g[i]==0)B=i; f[A]=B; } for(int i=0;i<len;i++) if(f[s[i]]==0){ falg=1;break; } if(falg){ printf("ERROR ");return 0; } for(int i=0;i<len;i++) printf("%c",f[s[i]]); return 0; }
序
【问题背景】
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=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } int main() { freopen("sort.in","r",stdin); freopen("sort.out","w",stdout); n=init();c[0]=-0x7fffffff; for(int i=1;i<=n;i++){ x=init(); if(x>c[num]){ c[++num]=x;continue; } int pos=lower_bound(c+1,c+1+num,x)-c; c[pos]=x; } printf("%d ",num); return 0; }
戏
【问题背景】
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][2],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=1;i<=n;i++){ scanf("%s",s[i]+1); for(int j=1;j<=n;j++) if(s[i][j]=='1')Add(i,j); } for(int x=1;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]=='1'){ if(f[x]==0){ f[x]=1;ans[x][0]=y;ans[x][1]=z; } else if(ans[x][0]>y){ ans[x][0]=y;ans[x][1]=z; } else if(ans[x][0]==y&&ans[x][1]>z) ans[x][1]=z; } } } if(f[x]){ printf("%d %d %d ",x,ans[x][0],ans[x][1]); falg=1;break; } } if(!falg)printf("-1 "); return 0; }
/* 这题真是够了 题目没说清楚 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]=1;S.push(u); for(int i=head[u];i;i=e[i].pre){ int v=e[i].v; if(dfn[v]==0){ 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[0]]=S.top();f[S.top()]=0;S.pop(); } c[++c[0]]=S.top();f[S.top()]=0;S.pop(); if(c[0]<3)c[0]=0; else { sum++;falg=1; for(int i=c[0];i>=1;i--) G[sum].push_back(c[i]); } } } void Printf(){ for(int k=1;k<=sum;k++) if(G[k].size()>=3){ int x,y,z;x=G[k][0]; for(int i=0;i<G[k].size()-1;i++){ y=G[k][i];z=G[k][i+1]; if(s[z][x]=='1'){ printf("%d %d %d ",x,y,z);break; } } break; } } int main() { freopen("game.in","r",stdin); freopen("game.ans","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",s[i]+1); for(int j=1;j<=n;j++) if(s[i][j]=='1')Add(i,j); } for(int i=1;i<=n;i++){ if(dfn[i]==0)Tarjan(i); if(falg){ Printf();break; } } if(!falg)printf("-1 "); return 0; }