10.26 noip模拟试题

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\n");return 0;
    }
    for(int i=0;i<len;i++)
        printf("%c",f[s[i]]);
    return 0;
}
View Code


【问题背景】
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\n",num);
    return 0;
}
View Code


【问题背景】
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\n",x,ans[x][0],ans[x][1]);
            falg=1;break;
        }
    }
    if(!falg)printf("-1\n");
    return 0;
}
View Code
/*
这题真是够了 题目没说清楚
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\n",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\n");
    return 0;
}
View Code

 

posted @ 2016-10-26 16:30  一入OI深似海  阅读(404)  评论(0编辑  收藏  举报