清北第二套题

                      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个密文都有满足条件的对应明文字符时,剩下的那个密文字符与剩下的明文字符对应。就这样丢了10分。

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 1100
#define ll long long
using namespace std;
string s1,s2,s3;
int l,sum=0;
char ans[N];
int ff[30];
bool f[30]={0};
int main()
{
    freopen("enc.in","r",stdin);
    freopen("enc.ans","w",stdout);
    
    cin>>s1>>s2>>s3;
    l=s2.length();
    for (int i=0;i<l;i++)
      {
            int x=s2[i]-'a'+1,y=s1[i]-'a'+1;
          if (!ff[x]&&!f[y]) ff[x]=y,f[y]=1,sum++;
          else if (ff[x]==y) ff[x]=y;
          else
             {
                  cout<<"ERROR"<<endl;
                  return 0;
             }
      }
      
    if (sum==25)//特判,当25个密文字符都有对应的明文字符时,最后一个密文字符与明文字符相匹配 
      {
           int bj;
           for (int i=1;i<=26;i++)
             if (!ff[i]) bj=i;
           for (int i=1;i<=26;i++)
             if (!f[i]) ff[bj]=i;
      }
      
    l=s3.length();
    for (int i=0;i<l;i++)
      {
          int j=s3[i]-'a'+1;
          if (ff[j]) ans[i]=char(ff[j]+'a'-1);
          else
             {
                  cout<<"ERROR"<<endl;
                  return 0;
             }
      }
     
      
    cout<<ans<<endl;
    
    fclose(stdin);
    fclose(stdout);
    
    return 0;
}
模拟

 

 

                                            序
【问题背景】
     zhx 给他的妹子们排序。
【问题描述】
     zhx 有 N 个妹子,他对第 i 个妹子的好感度为ai, 且所有ai ,两两不相等。现在 N 个妹子随意站成一排,他要将她们根据好感度从小到大排序。他使用的是冒泡排序算法(详见下) 。如果排序过程中好感度为ai的妹子和好感度为aj的妹子发生了交换,那么她们之间会发生一场口角。

     现在zhx 想知道,给定妹子的初始排列,在排序完成后,最多存在多少个妹子,她们任意两人之间没发生过口角。

     正式地,考虑对数组ai进行冒泡排序,如果ai 和aj 在排序过程中发生交换,那么在两个元素之间连一条边。 你需要求出, 排序结束后, 最多存在多少个元素,其中任意两个元素之间不存在连边。冒牌排序算法如下:

 


【输入格式】
    第一行两个整数 N,表示妹子数量。
    接下来一行 N 个整数ai,表示初始第 i 个妹子的好感度。
【输出格式】
    一行一个整数,表示最多满足要求的妹子的个数。
【样例输入】
   3
   3 1 2
【样例输出】
   2
【样例解释】
   {1, 2}。
【数据规模与约定】
   对于30%的数据,1 ≤N ≤ 16。
   对于70%的数据,1 ≤ N ≤ 50。
   对于100%的数据,1 ≤ N ≤ 100000, 0 ≤ ai < N。

 

 

题解:根据冒泡排序的性质,假定i小于j,若ai<aj则两个妹子绝对不会发生交换。因此求出最大上升子序列,他的长度即为答案。求最大上升子序列时,用上二分优化,可将时间降为o(nlogn)。

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 100100
#define ll long long
using namespace std;
int n,k=0,ans=0;
int a[N];
int num[N]={0};
int f[N];
int erfen(int l,int r,int q)
{
    if (l>r) return l;
    int mid=(l+r)>>1;
    if (f[mid]>q) erfen(l,mid-1,q);
      else erfen(mid+1,r,q);
}
int main()
{
    freopen("sort.in","r",stdin);
    freopen("sort.ans","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    f[++k]=a[1];
    
    for (int i=2;i<=n;i++)
      {
          int j=erfen(0,k,a[i]);
        f[j]=a[i];
        if (j>k) k=j;
      }
      
    cout<<k<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}
二分,dp

 

 

                                       
【问题背景】
     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%的数据。1 ≤ N ≤ 500。
     对于80%的数据,1 ≤ N ≤ 1000。
     对于100%的数据,1 ≤ N ≤ 5000

 

题解:原谅本蒟蒻不会此题,只会打最简单的暴力。弱弱的30分。由于题目没规定输出顺序,本应该能稳过55%的数据,最后只得30分。

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 5100
#define ll long long
using namespace std;
int n;
char ch;
bool f[N][N]={0},ff=1;
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.ans","w",stdout);
    
    scanf("%d",&n);
    scanf("%c",&ch);
    for (int i=1;i<=n;i++)
      {
          for(int j=1;j<=n;j++)
            {
                 scanf("%c",&ch); 
                 f[i][j]=int (ch-'0');
          }
        scanf("%c",&ch);
         
      } 
     for (int i=1;i<=n;i++)
       for (int j=1;j<=n;j++)
         if (f[i][j])
           for (int k=1;k<=n;k++)
             if (f[j][k]&&f[k][i]) 
               {
                     cout<<i<<' '<<j<<' '<<k<<endl;
                     return 0;
               }
    cout<<-1<<endl;
        
    fclose(stdin);
    fclose(stdout);
    
    return 0;
}
暴力枚举,30

 

posted @ 2016-10-26 16:06  外婆桥  阅读(384)  评论(0编辑  收藏  举报