1、银河英雄传说
题目描述
公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展。
宇宙历七九九年,银河系的两大军事集*在巴米利恩星域爆发战争。泰山压顶集**宇宙舰队司令莱因哈特率领十万余艘战舰出征,气吞山河集*点名将杨威利组织麾下三万艘战舰迎敌。
杨威利擅长排兵布阵,巧妙运用各种战术屡次以少胜多,难免恣生骄气。在这次决战中,他将巴米利恩星域战场划分成30000列,每列依次编号为1, 2, …, 30000。之后,他把自己的战舰也依次编号为1, 2, …, 30000,让第i号战舰处于第i列(i = 1, 2, …, 30000),形成“一字长蛇阵”,诱敌深入。这是初始阵形。当进犯之敌到达时,杨威利会多次发布合并指令,将大部分战舰集中在某几列上,实施密集攻击。合并指令为M i j,含义为让第i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。显然战舰队列是由处于同一列的一个或多个战舰组成的。合并指令的执行结果会使队列增大。
然而,老谋深算的莱因哈特早已在战略上取得了主动。在交战中,他可以通过庞大的情报网络随时监听杨威利的舰队调动指令。
在杨威利发布指令调动舰队的同时,莱因哈特为了及时了解当前杨威利的战舰分布情况,也会发出一些询问指令:C i j。该指令意思是,询问电脑,杨威利的第i号战舰与第j号战舰当前是否在同一列中,如果在同一列中,那么它们之间布置有多少战舰。
作为一个资深的高级程序设计员,你被要求编写程序分析杨威利的指令,以及回答莱因哈特的询问。
最终的决战已经展开,银河的历史又翻过了一页……
宇宙历七九九年,银河系的两大军事集*在巴米利恩星域爆发战争。泰山压顶集**宇宙舰队司令莱因哈特率领十万余艘战舰出征,气吞山河集*点名将杨威利组织麾下三万艘战舰迎敌。
杨威利擅长排兵布阵,巧妙运用各种战术屡次以少胜多,难免恣生骄气。在这次决战中,他将巴米利恩星域战场划分成30000列,每列依次编号为1, 2, …, 30000。之后,他把自己的战舰也依次编号为1, 2, …, 30000,让第i号战舰处于第i列(i = 1, 2, …, 30000),形成“一字长蛇阵”,诱敌深入。这是初始阵形。当进犯之敌到达时,杨威利会多次发布合并指令,将大部分战舰集中在某几列上,实施密集攻击。合并指令为M i j,含义为让第i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。显然战舰队列是由处于同一列的一个或多个战舰组成的。合并指令的执行结果会使队列增大。
然而,老谋深算的莱因哈特早已在战略上取得了主动。在交战中,他可以通过庞大的情报网络随时监听杨威利的舰队调动指令。
在杨威利发布指令调动舰队的同时,莱因哈特为了及时了解当前杨威利的战舰分布情况,也会发出一些询问指令:C i j。该指令意思是,询问电脑,杨威利的第i号战舰与第j号战舰当前是否在同一列中,如果在同一列中,那么它们之间布置有多少战舰。
作为一个资深的高级程序设计员,你被要求编写程序分析杨威利的指令,以及回答莱因哈特的询问。
最终的决战已经展开,银河的历史又翻过了一页……
输入
输入的第一行有一个整数T(1<=T<=500,000),表示总共有T条指令。
以下有T行,每行有一条指令。指令有两种格式:
1.M i j :i和j是两个整数(1<=i , j<=30000),表示指令涉及的战舰编号。该指令是莱因哈特窃听到的杨威利发布的舰队调动指令,并且保证第i号战舰与第j号战舰不在同一列。
2.C i j :i和j是两个整数(1<=i , j<=30000),表示指令涉及的战舰编号。该指令是莱因哈特发布的询问指令。
以下有T行,每行有一条指令。指令有两种格式:
1.M i j :i和j是两个整数(1<=i , j<=30000),表示指令涉及的战舰编号。该指令是莱因哈特窃听到的杨威利发布的舰队调动指令,并且保证第i号战舰与第j号战舰不在同一列。
2.C i j :i和j是两个整数(1<=i , j<=30000),表示指令涉及的战舰编号。该指令是莱因哈特发布的询问指令。
输出
你的程序应当依次对输入的每一条指令进行分析和处理:
如果是杨威利发布的舰队调动指令,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息;
如果是莱因哈特发布的询问指令,你的程序要输出一行,仅包含一个整数,表示在同一列上,第i号战舰与第j号战舰之间布置的战舰数目。如果第i号战舰与第j号战舰当前不在同一列上,则输出-1。
如果是杨威利发布的舰队调动指令,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息;
如果是莱因哈特发布的询问指令,你的程序要输出一行,仅包含一个整数,表示在同一列上,第i号战舰与第j号战舰之间布置的战舰数目。如果第i号战舰与第j号战舰当前不在同一列上,则输出-1。
样例输入
4
M 2 3
C 1 2
M 2 4
C 4 2
样例输出
-1
1
思路:题目的两个指令摆明了是并查集。和普通的并查集区别的是查询时需要输出查询两舰之间的舰数。这就要求了合并时要有序,但线性不优化的并查集肯定会超时,于是可以用一个数组s来储存当前战舰的权值,在每次合并时更新i列舰队的头的权值和父结点。在每次执行search操作时更新其他节点的权值和父结点。代码中b数组为当前列的集合大小,方便更新权值。
代码:

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 3e4; 4 int f[maxn+5], s[maxn+5], b[maxn+5]; 5 6 void init(); 7 int search(int); 8 void merge(int, int); 9 10 int main() 11 { 12 int T; 13 scanf("%d ",&T); 14 char op; 15 int x, y; 16 init(); 17 while (T--) 18 { 19 scanf("%c %d %d ",&op, &x, &y); 20 if (op == 'M') 21 { 22 merge(x, y); 23 } 24 else if (op == 'C') 25 { 26 if (search(x) == search(y)) 27 { 28 printf("%d ",abs(s[x] - s[y]) - 1); 29 } 30 else 31 { 32 printf("-1 "); 33 } 34 } 35 } 36 return 0; 37 } 38 void init() 39 { 40 for (int i=1; i<=maxn; i++) 41 f[i] = i, b[i] = 1, s[i] = 0; 42 } 43 int search(int x) 44 { 45 if (f[x] == x) 46 return x; 47 int k = f[x]; 48 f[x] = search(f[x]); 49 s[x] += s[k]; 50 b[x] = b[f[x]]; 51 return f[x]; 52 } 53 void merge(int x, int y) 54 { 55 int fx = search(x); 56 int fy = search(y); 57 f[fx] = fy; 58 s[fx] += b[fy]; 59 b[fx] += b[fy]; 60 b[fy] = b[fx]; 61 }
2、破译密文
题目描述
信息的明文是由0和1组成的非空序列。但在网络通信中,为了信息的安全性,常对明文进行加密,用密文进行传输。密文是由0、1和若干个密码字母组成,每个密码字母代表不超过100位不同的01串,例如,密文=011a0bf00a01。密码破译的关键是确定每个密码的含义。
经过长期统计分析,现在知道了每个密码的固定长度,如今,我方又截获了敌方的两段密文S1和S2,并且知道S1=S2,即两段密文代表相同的明文。你的任务是帮助情报人员对给定的两段密文进行分析,看一看有多少种可能的明文,保证密文是合法的,不用判错。
输入
第一行为一个字符串s1
第二行为字符串s2
第三行为整数n,表示有n个小写字母(0<n<=26)
接着n行,每行为一个字符和一个整数,字符的长度
输出
为一行,为共有多少中明文的可能
样例输入
100ad1 cc1 4 a 2 d 3 c 4 b 50
样例输出
2
思路:把每个字母拆分成与其等长的字串,例如c1,c2,c3,c4,再一一对应将每一对对应的字符并入同一个集合,最后和0同集合的就是0,和1同集合的就是1,其他集合就是未知的,可以是0或1,答案就是2的未知集合数次方。因为我做的题目明确表示保证密文是合法的,但我在别的地方看到的题目并没有保证密文合法,所以补充判断密文不合法的要点:1、字符串不等长2、某两个有明确指定的对应字符不相同(即一个是1一个是0)。

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 10010; 4 char c, s1[maxn], s2[maxn]; 5 int n, l[27], cnt, zj[27][110], f[maxn]; 6 bool vis[maxn]; 7 vector <int> t1, t2; 8 9 int find(int x); 10 void deal(char *s, int &len, vector <int> &a); 11 void init(int n); 12 13 int main() 14 { 15 ios::sync_with_stdio(false); 16 cnt = 1; 17 cin >> s1 >> s2 >> n; 18 int l1 = strlen(s1), l2 = strlen(s2); 19 for (int i=1; i<=n; i++) 20 { 21 cin >> c; 22 cin >> l[c - 'a']; 23 for (int j=1; j<=l[c - 'a']; j++) 24 { 25 zj[c - 'a'][j] = ++cnt; 26 } 27 } 28 deal(s1, l1, t1); 29 deal(s2, l2, t2); 30 init(cnt); 31 for (int i=0;i<l1;i++) { 32 int x = t1[i], y = t2[i], fx = find(x), fy = find(y); 33 if (fx != fy) 34 { 35 if (fx == 1 || fx == 0) 36 f[fy] = fx; 37 else 38 f[fx] = fy; 39 } 40 } 41 42 int ans = 0; 43 for (int i=2;i<=cnt;i++) 44 if (f[i] == i && vis[i]) ans++; 45 cout << (1 << ans) << endl; 46 return 0; 47 } 48 49 int find(int x) 50 { 51 if (f[x] == x) 52 return x; 53 f[x] = find(f[x]); 54 return f[x]; 55 } 56 void deal(char *s, int &len, vector <int> &a) 57 { 58 for (int i=0; i<=len; i++) 59 { 60 if (s[i] == '0' || s[i] == '1') 61 a.push_back(s[i]-'0'); 62 else 63 for (int j=1; j<=l[s[i]-'a']; j++) 64 { 65 vis[zj[s[i]-'a'][j]] = true; 66 a.push_back(zj[s[i]-'a'][j]); 67 } 68 } 69 len = a.size(); 70 } 71 void init(int n) 72 { 73 for (int i=0;i<=n;i++) { 74 f[i] = i; 75 } 76 }