首页 > 技术文章 > noip2009题解

zyx45889 2016-11-17 19:36 原文

描述

R 国和 S国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动。
历尽艰险后,潜伏于 S国的 R 国间谍小 C 终于摸清了 S国军用密码的编码规则:
1. S 国军方内部欲发送的原信息经过加密后在网络上发送,原信息的内容与加密后所
得的内容均由大写字母‘A’-‘Z’构成(无空格等其他字符) 。
2. S国对于每个字母规定了对应的“密字” 。加密的过程就是将原信息中的所有字母替
换为其对应的“密字” 。
3. 每个字母只对应一个唯一的“密字” ,不同的字母对应不同的“密字” 。 “密字”可以
和原字母相同。
例如,若规定‘A’的密字为‘A’ , ‘B’的密字为‘C’ (其他字母及密字略) ,则原信
息“ABA”被加密为“ACA” 。
现在,小 C 通过内线掌握了 S 国网络上发送的一条加密信息及其对应的原信息。小 C
希望能通过这条信息,破译 S 国的军用密码。小 C 的破译过程是这样的:扫描原信息,对
于原信息中的字母 x(代表任一大写字母) ,找到其在加密信息中的对应大写字母 y,并认为
在密码里 y是 x 的密字。如此进行下去直到停止于如下的某个状态:

1. 所有信息扫描完毕, ‘A’-‘Z’ 所有 26 个字母在原信息中均出现过并获得了相应
的“密字” 。
2. 所有信息扫描完毕,但发现存在某个(或某些)字母在原信息中没有出现。
3. 扫描中发现掌握的信息里有明显的自相矛盾或错误(违反 S国密码的编码规则) 。例
如某条信息“XYZ”被翻译为“ABA”就违反了“不同字母对应不同密字”的规则。

在小 C 忙得头昏脑涨之际,R 国司令部又发来电报,要求他翻译另外一条从 S 国刚刚
截取到的加密信息。现在请你帮助小 C:通过内线掌握的信息,尝试破译密码。然后利用破
译的密码,翻译电报中的加密信息。

格式

输入格式

输入共3行,每行为一个长度在 1 到100 之间的字符串。
第 1 行为小C 掌握的一条加密信息。
第 2 行为第1 行的加密信息所对应的原信息。
第 3 行为R国司令部要求小 C 翻译的加密信息。
输入数据保证所有字符串仅由大写字母‘A’-‘Z’构成,且第 1 行长度与第 2 行相等。

输出格式

输出共1行。
若破译密码停止时出现 2,3 两种情况,请你输出“Failed” (不含引号,注意首字母大
写,其它小写) 。
否则请输出利用密码翻译电报中加密信息后得到的原信息。

样例1

样例输入1[复制]

 
AA 
AB 
EOWIE 

样例输出1[复制]

 
Failed 

样例2

样例输入2[复制]

 
QWERTYUIOPLKJHGFDSAZXCVBN 
ABCDEFGHIJKLMNOPQRSTUVWXY 
DSLIEWO 

样例输出2[复制]

 
Failed

样例3

样例输入3[复制]

 
MSRTZCJKPFLQYVAWBINXUEDGHOOILSMIJFRCOPPQCEUNYDUMPP
YIZSDWAHLNOVFUCERKJXQMGTBPPKOIYKANZWPLLVWMQJFGQYLL
FLSO 

样例输出3[复制]

 
NOIP

限制

每个测试点1s

模拟,注意反向也需要判断是否一对一

 1 #include<iostream>
 2 #include<string.h>
 3 #include<stdio.h>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #define N 26
 7 #define M 105
 8 using namespace std;
 9 char s1[M],s2[M],s3[M];
10 char table[N];
11 
12 int main()
13 {
14     scanf("%s%s%s",s1,s2,s3);
15     for(int i=0;i<strlen(s1);i++)
16     {
17         if(table[s1[i]-'A']==0)
18          table[s1[i]-'A']=s2[i];
19         else if(table[s1[i]-'A']!=s2[i])
20         {
21             cout<<"Failed"<<endl;
22             return 0;
23         }
24     }
25     for(int i=0;i<N;i++)
26      if(table[i]==0)
27      {
28          cout<<"Failed"<<endl;
29          return 0;
30      }
31     for(int i=0;i<N;i++)
32      for(int j=i+1;j<N;j++)
33       if(table[i]==table[j])
34      {
35          cout<<"Failed"<<endl;
36          return 0;
37      }
38     for(int i=0;i<strlen(s3);i++)
39      cout<<table[s3[i]-'A'];
40     cout<<endl;
41     return 0;
42 }

描述

Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson。现
在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数 c1和 c2 的最大公约数和最小公倍数。现
在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公
倍数”之类问题的“逆问题” ,这个问题是这样的:已知正整数 a0,a1,b0,b1,设某未知正整
数 x 满足:
1. x 和 a0 的最大公约数是 a1;
2. x 和b0 的最小公倍数是 b1。
Hankson 的“逆问题”就是求出满足条件的正整数 x。但稍加思索之后,他发现这样的
x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的 x 的个数。请你帮
助他编程求解这个问题。

格式

输入格式

第一行为一个正整数 n,表示有 n 组输入数据。接下来的 n 行每
行一组输入数据,为四个正整数 a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入
数据保证 a0能被 a1 整除,b1 能被 b0整除。

输出格式

共n 行。每组输入数据的输出结果占一行,为一个整数。
对于每组数据:若不存在这样的 x,请输出 0;
若存在这样的 x,请输出满足条件的 x 的个数;

样例1

样例输入1[复制]

 
2 
41 1 96 288 
95 1 37 1776 

样例输出1[复制]

 
6 
2 

限制

每个测试点1s

一旦沾上数论,除了不会我不能再说什么TAT

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<cstdlib>
 5 using namespace std;
 6 int n;
 7 int a0,a1,b0,b1;
 8 int k1,k2;
 9 int answer;
10 int x;
11 
12 int gcd(int a,int b)
13 {
14     if(b==0)return a;
15     return gcd(b,a%b);
16 }
17 
18 int main()
19 {
20     scanf("%d",&n);
21     while(n--)
22     {
23         answer=0;
24         scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
25         if(a0%a1||b1%b0)
26         {
27             printf("0\n");
28             continue;
29         }
30         k1=a0/a1;
31         k2=b1/b0;
32         for(int i=1;i*i<=b1;i++)
33          if(b1%i==0)
34          {
35              x=i;
36              if(x%a1==0&&gcd(k1,x/a1)==1&&gcd(k2,b1/x)==1)answer++;
37             x=b1/i;
38             if(x!=i&&x%a1==0&&gcd(k1,x/a1)==1&&gcd(k2,b1/x)==1)answer++; 
39          }
40         printf("%d\n",answer);
41     }
42     return 0;
43 }

描述

C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市。任意两个
城市之间最多只有一条道路直接相连。这 m 条道路中有一部分为单向通行的道路,一部分
为双向通行的道路,双向通行的道路在统计条数时也计为 1 条。
C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价
格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。
商人阿龙来到 C 国旅游。当他得知同一种商品在不同城市的价格可能会不同这一信息
之后,便决定在旅游的同时,利用商品在不同城市中的差价赚回一点旅费。设 C 国 n 个城
市的标号从 1~ n,阿龙决定从 1 号城市出发,并最终在 n 号城市结束自己的旅行。在旅游的
过程中,任何城市可以重复经过多次,但不要求经过所有 n 个城市。阿龙通过这样的贸易方
式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品——水晶球,并在之后经过的另
一个城市卖出这个水晶球,用赚取的差价当做旅费。由于阿龙主要是来 C 国旅游,他决定
这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。
假设 C 国有 5 个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路
为单向通行,双向箭头表示这条道路为双向通行。

图片

假设 1~n 号城市的水晶球价格分别为 4,3,5,6,1。
阿龙可以选择如下一条线路:1->2->3->5,并在 2 号城市以 3 的价格买入水晶球,在 3
号城市以 5的价格卖出水晶球,赚取的旅费数为 2。
阿龙也可以选择如下一条线路 1->4->5->4->5,并在第 1 次到达 5 号城市时以 1 的价格
买入水晶球,在第 2 次到达 4 号城市时以 6 的价格卖出水晶球,赚取的旅费数为 5。

现在给出 n个城市的水晶球价格,m条道路的信息(每条道路所连接的两个城市的编号
以及该条道路的通行情况) 。请你告诉阿龙,他最多能赚取多少旅费。

格式

输入格式

第一行包含 2 个正整数 n 和 m,中间用一个空格隔开,分别表示城市的数目和道路的
数目。
第二行 n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这 n 个城
市的商品价格。
接下来 m行, 每行有 3 个正整数, x, y, z, 每两个整数之间用一个空格隔开。 如果 z=1,
表示这条道路是城市 x到城市 y之间的单向道路;如果 z=2,表示这条道路为城市 x 和城市
y之间的双向道路。

输出格式

输出共1 行, 包含 1 个整数, 表示最多能赚取的旅费。 如果没有进行贸易,
则输出 0。

样例1

样例输入1[复制]

 
5 5 
4 3 5 6 1 
1 2 1 
1 4 1 
2 3 2 
3 5 1 
4 5 2 

样例输出1[复制]

 
5

限制

每个测试点1s

输入数据保证 1 号城市可以到达n 号城市。
对于 10%的数据,1≤n≤6。
对于 30%的数据,1≤n≤100。
对于 50%的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。
对于 100%的数据,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤各城市
水晶球价格≤100。

按照spfa的思路跑dp更新每个点能够到达的最大值和能够被到达的最小值
  1 #include<iostream>
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #define N 100005
  7 #define M 500005
  8 #define inf 0x3f3f3f3f
  9 using namespace std;
 10 int n,m;
 11 int weight[N];
 12 int beg[N];
 13 int cnt;
 14 int ans;
 15 int flag[N];
 16 int d1[N],d2[N];
 17 
 18 class Queue
 19 {
 20 private:
 21     int front,rear,size;
 22     int queue[N*4];
 23 public:
 24     Queue()
 25     {
 26         front=size=0;
 27         rear=-1;
 28     }
 29     int Dequeue()
 30     {
 31         int x=queue[front];
 32         front++;
 33         if(front==4*N)
 34          front=0;
 35         size--;
 36         return x;
 37     }
 38     void Enqueue(int x)
 39     {
 40         rear++;
 41         if(rear==N*4)
 42          rear=0;
 43         queue[rear]=x;
 44         size++;
 45     }
 46     int Getsize()
 47     {
 48         return size;
 49     }
 50 }mq;
 51 
 52 struct edge
 53 {
 54     int b,next,tag;
 55 }E[M*4];
 56 
 57 void addedge(int a,int b,int f,int v)
 58 {
 59     E[cnt].b=b;
 60     E[cnt].next=beg[a];
 61     beg[a]=cnt;
 62     E[cnt].tag=v;
 63     cnt++;
 64     if(f==2)
 65      addedge(b,a,1,v);
 66 }
 67 
 68 void spfa1()
 69 {
 70     memset(d1,-inf,sizeof(d1));
 71     d1[n-1]=weight[n-1];
 72     flag[n-1]=1;
 73     mq.Enqueue(n-1);
 74     while(mq.Getsize())
 75     {
 76         int now=mq.Dequeue();
 77         for(int i=beg[now];i!=-1;i=E[i].next)
 78          if(E[i].tag==0&&(d1[now]>d1[E[i].b]||d1[E[i].b]<weight[E[i].b]))
 79          {
 80              d1[E[i].b]=max(d1[now],weight[E[i].b]);
 81              if(flag[E[i].b]==0)
 82              {
 83                  mq.Enqueue(E[i].b);
 84                  flag[E[i].b]=1;
 85             }
 86          }
 87         flag[now]=0;
 88     }
 89 }
 90 
 91 void spfa2()
 92 {
 93     memset(d2,inf,sizeof(d2));
 94     d2[0]=weight[0];
 95     flag[0]=1;
 96     mq.Enqueue(0);
 97     while(mq.Getsize())
 98     {
 99         int now=mq.Dequeue();
100         for(int i=beg[now];i!=-1;i=E[i].next)
101          if(E[i].tag==1&&(d2[now]<d2[E[i].b]||d2[E[i].b]>weight[E[i].b]))
102          {
103              d2[E[i].b]=min(d2[now],weight[E[i].b]);
104              if(flag[E[i].b]==0)
105              {
106                  mq.Enqueue(E[i].b);
107                  flag[E[i].b]=1;
108             }
109          }
110         flag[now]=0;
111     }
112 }
113 
114 int main()
115 {
116     int a,b,c;
117     scanf("%d%d",&n,&m);
118     memset(beg,-1,sizeof(beg));
119     for(int i=0;i<n;i++)
120      scanf("%d",&weight[i]);
121     for(int i=0;i<m;i++)
122      scanf("%d%d%d",&a,&b,&c),addedge(a-1,b-1,c,1),addedge(b-1,a-1,c,0);
123     spfa1();
124     spfa2();
125     for(int i=0;i<n;i++)
126      ans=max(ans,d1[i]-d2[i]);
127     cout<<ans<<endl;
128     return 0;
129 }

描述

小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他
们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教,
Z 博士拿出了他最近发明的“靶形数独” ,作为这两个孩子比试的题目。
靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有 9 个 3 格宽×3 格
高的小九宫格(用粗黑色线隔开的) 。在这个大九宫格中,有一些数字是已知的,根据这些
数字,利用逻辑推理,在其他的空格上填入 1到 9 的数字。每个数字在每个小九宫格内不能
重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即
每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。 (如图)
图片
上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红
色区域)每个格子为 9 分,再外面一圈(蓝色区域)每个格子为 8分,蓝色区域外面一圈(棕
色区域)每个格子为 7分,最外面一圈(白色区域)每个格子为 6 分,如上图所示。比赛的
要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法) ,而且要争取
更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字
的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829。游
戏规定,将以总分数的高低决出胜负。
图片
由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能
够得到的最高分数。

格式

输入格式

一共 9 行。每行 9 个整数(每个数都在 0—9 的范围内) ,表示一个尚未填满的数独方
格,未填的空格用“0”表示。每两个数字之间用一个空格隔开。

输出格式

输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-1。

样例1

样例输入1[复制]

 
7 0 0 9 0 0 0 0 1 
1 0 0 0 0 5 9 0 0 
0 0 0 2 0 0 0 8 0 
0 0 5 0 2 0 0 0 3 
0 0 0 0 0 0 6 4 8 
4 1 3 0 0 0 0 0 0 
0 0 7 0 0 2 0 9 0 
2 0 1 0 6 0 8 0 4 
0 8 0 5 0 4 0 1 2 

样例输出1[复制]

 
2829 

样例2

样例输入2[复制]

 
0 0 0 7 0 2 4 5 3 
9 0 0 0 0 8 0 0 0 
7 4 0 0 0 5 0 1 0 
1 9 5 0 8 0 0 0 0 
0 7 0 0 0 0 0 2 5 
0 3 0 5 7 9 1 0 8 
0 0 0 6 0 1 0 0 0 
0 6 0 9 0 0 0 0 1 
0 0 0 0 0 0 0 0 6 

样例输出2[复制]

 
2852

限制

每个测试点2s

提示

40%的数据,数独中非 0数的个数不少于 30。
80%的数据,数独中非 0数的个数不少于 26。
100%的数据,数独中非 0 数的个数不少于 24。

搜索,这个题是抄的别人家的代码,主要原因是这份写得实在是漂亮作为一个写搜索题的模板来看完全值得
 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 using namespace std;
 7 int G[9][9];
 8 int h[9][10]={0};    //h[i][j]表示第i行(横向)有没有j 
 9 int l[9][10]={0};    //l[i][j]表示第i列(纵向)有没有j
10 int q[9][10]={0};    //q[i][j]表示第i个九宫格有没有j
11 
12 int getscore()
13 {
14     int sum=0,k;
15     for(int i=0;i<9;i++)
16      for(int j=0;j<9;j++)
17      {
18             if(i==0||i==8||j==0||j==8)k=6;
19             else if(i==1||i==7||j==1||j==7)k=7;
20             else if(i==2||i==6||j==2||j==6)k=8;
21             else if(i==3||i==5||j==3||j==5)k=9;
22             else if(i==4&&j==4)k=10;
23             sum+=G[i][j]*k;
24      }
25     return sum;
26 }
27 
28 int getnum(int i,int j)
29 {//获取九宫格的编号 
30     return 3*(i/3)+(j/3);
31 }
32 
33 int update(int p,int x,int y,int a)
34 {
35     if(p==1)
36         G[x][y]=a;
37     else
38         G[x][y]=0; 
39     h[x][a]=p;
40     l[y][a]=p;
41     q[getnum(x,y)][a]=p;
42 }
43 
44 int isok(int i,int j,int x)
45 {
46     if(h[i][x]==0&&l[j][x]==0&&q[getnum(i,j)][x]==0)
47      return 1;
48     return 0;
49 }
50 
51 int ans=0;
52 
53 void dfs(int now)
54 {    
55     if(now==81)
56     {
57         ans=max(ans,getscore());
58         return;
59     }
60     int pi=now/9,pj=now-9*(now/9);
61     if(G[pi][pj]!=0)
62         dfs(now+1);
63     else
64     {
65         for(int x=1;x<=9;x++)
66         {
67             if(isok(pi,pj,x))
68             {
69                 update(1,pi,pj,x);
70                 dfs(now+1);
71                 update(0,pi,pj,x);
72             }
73         }
74     }
75 }
76 
77 int main()
78 {
79     int x;
80     for(int i=8;i>=0;i--)
81      for(int j=8;j>=0;j--)
82      {
83         scanf("%d",&x);
84         if(x!=0)update(1,i,j,x);
85      }
86     dfs(0);
87     if(ans==0)
88         printf("-1");
89     else
90         printf("%d",ans);
91     return 0;
92 } 

 

推荐阅读