数据结构 |
串 |
poj1035,poj3080,poj1936 |
排序 |
poj2388,poj2299 |
|
简单并查集的应用 |
poj1611 |
|
哈希表和二分查找等高效查找法 |
poj3349,poj3274,POJ2151(DP), poj1840,poj2002,poj2503 |
|
哈夫曼树 |
||
堆,优先队列 |
poj2442, poj1442 |
|
trie树 |
poj2513, poj2418 |
poj 1035
分三种情况考虑。替换的话出入的字符串和dictionary只有一个不相同的。插入、删除的话比较与dictionary中相同的个数。
poj 3080
暴力过了,原来还有这么好用的strstr()函数。无语,我在那模拟了一晚上。。。
用法:#include <string.h> 功能:从字符串haystack中寻找needle第一次出现的位置(不比较结束符NULL)。 说明:返回指向第一次出现needle位置的指针,如果没找到则返回NULL。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 15;
char dic[N][66], s_max[66], tmp[66];
int n;
int cmp() {
int ans, cnt, i, j, k;
ans = 0; //len = strlen(dic[0]);
for(i = 0; i < 60; ++i) {
for(j = i; j < 60; ++j) {
cnt = 0;
for(k = i; k <= j; ++k) tmp[cnt++] = dic[0][k];
tmp[cnt] = 0;
for(k = 1; k < n; ++k)
if(strstr(dic[k], tmp) == 0) break;
if(k < n) continue;
if(cnt > ans) {
ans = cnt;
strcpy(s_max, tmp);
} else if(cnt == ans && strcmp(s_max, tmp) > 0) {
strcpy(s_max, tmp);
}
}
}
return ans;
}
int main() {
//freopen("data.in", "r", stdin);
int t, i;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
getchar();
for(i = 0; i < n; ++i) {
cin.getline(dic[i], 66);
//puts(dic[i]);
}
if(cmp() < 3) puts("no significant commonalities");
else puts(s_max);
}
return 0;
}
poj 1936 水题
poj 2388 复习了一下堆排序
poj 2299
题意是给一个无序的序列,两两交换两个元素的位置(这两个元素必须相邻)求需要交换多少次使这个序列成为有序不递减序列
其实是让求逆序数是多少。这里用二路归并排序实现O(nlogn)的复杂度求逆序数。在实现一个二路归并排序过程中,前一半的序列x[i]跟后一半的序列y[j]分别有序。当出现x[i] > y[j]时,说明y[j]前边有mid - i + 1个数比y[j]大,累计逆序数。在网上看到一个很简洁的实现归并排序的代码,记下当模板
1 long long merge_sort(int l, int r) {
2 int mid, p, q, i, j, len;
3 long long ans = 0;
4
5 if(l >= r) return 0;
6 mid = (l + r) >> 1;
7 len = r - l + 1;
8
9 ans += merge_sort(l, mid);
10 ans += merge_sort(mid + 1, r);
11
12 p = l; q = mid + 1;
13 j = l;
14
15
16 for(i = 0; i < len; ++i) {
17 if((q > r) || (num[p] < num[q] && p <= mid)) {
18 t[j++] = num[p++];
19 } else {
20 ans += mid - p + 1;
21 t[j++] = num[q++];
22 }
23 }
24 for(i = l; i <= r; ++i) num[i] = t[i];
25
26 return ans;
27 }
poj 1611
建关系的时候写成O(n^2)了,跟si一样的700+ms过了,改过来后16+ms。貌似这题的数据不大,路径压缩起不到作用。=、=//
poj 3349
对每次输入的六个数求和取模,得到一个键值key,对键值相同的两个序列进行判断(这里用挂链存储),看是否匹配。判断匹配时可以把一个序列x增加一倍,扩展成长度为12的,比如
x: 1, 2, 3, 4, 5, 6
-> x: 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6
然后跟
另一个正序匹配一遍,倒序匹配一遍,如果可以匹配,返回true,否则返回false。
poj 3274
从大牛那学来的。。。
sum[i][j] 表示第1到i个牛,j特征的总数。
sum[i][0] - sum[j][0] == sum[i][1] - sum[j][1] == sum[i][2] - sum[j][2] = ...
变形得
sum[i][1] - sum[i][0] == sum[j][1] - sum[j][0];
sum[i][2] - sum[i][0] == sum[j][2] - sum[j][0];
。。。
令c[i][L] = sum[i][L] - sum[i][0];
比较c[i][...] == c[j][...]使 i - j 最大;
可以用hashcode把c[i][...]折帖成一个值p,记录hash[p] = i;
主过程:
1 int main() {
2 //freopen("data.in", "r", stdin);
3
4 int n, k, i, j;
5 int x, p, ans;
6 while(~scanf("%d%d", &n, &k)) {
7 memset(sum, 0, sizeof(sum));
8 memset(hash, -1, sizeof(hash));
9 memset(c, 0, sizeof(c));
10 memset(a, 0, sizeof(a));
11
12 hash[hashcode(c[0], k)] = 0;
13 ans = 0;
14 for(i = 1; i <= n; ++i) {
15 scanf("%d", &x);
16 for(j = 0; j < k; ++j) {
17 a[i][j] = x % 2;
18 x >>= 1;
19 sum[i][j] = sum[i-1][j] + a[i][j];
20 c[i][j] = sum[i][j] - sum[i][0];
21 }
22 p = hashcode(c[i], k);
23 while(hash[p] != -1) {
24 for(j = 0; j < k; ++j) {
25 if(c[i][j] != c[hash[p]][j]) break;
26 }
27 if(j == k) {
28 ans = max(ans, i - hash[p]); break;
29 }
30 p++;
31 }
32 if(hash[p] == -1) hash[p] = i;
33 }
34 printf("%d\n", ans);
35 }
36 return 0;
37 }
POJ 2151
貌似是道dp题。。。概率论没学好,在样例上纠结很长时间。
设事件A = {所有队AC至少一题的概率},事件B = {所有的队都AC sum([1, N)题的概率)};
用dp[i][j] 表示前i个题AC j道题的概率.
dp[i][j] = dp[i-1][j] * (1 - p[i]) + dp[i-1][j-1] * p[i];
memset(dp, 0, sizoef(dp));
dp[0][0] = 1;
dp[i][0] = dp[i-1][0] * (1 - p[i]);
渣代码
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <cstdlib>
5
6 using namespace std;
7
8 const int N = 100;
9
10 double dp[N][N];
11 double p[N];
12
13 int main() {
14 //freopen("data.in", "r", stdin);
15
16 int M, T, N;
17 int i, j;
18 double tol, d, cnt;
19 while(~scanf("%d%d%d", &M, &T, &N)) {
20 if(!M && !T && !N) break;
21 tol = 1; d = 1;
22 while(T--) {
23 memset(dp, 0, sizeof(dp));
24 dp[0][0] = 1;
25
26 for(j = 1; j <= M; ++j) {
27 scanf("%lf", &p[j]);
28 dp[j][0] = dp[j-1][0] * (1 - p[j]);
29 }
30
31 tol *= (1 - dp[M][0]);
32 if(N == 1) {d = 0; continue;}
33
34 for(i = 1; i <= M; ++i) {
35 for(j = 1; j <= i && j < N; ++j) {
36 dp[i][j] = dp[i-1][j]*(1 - p[i]) + dp[i-1][j-1]*p[i];
37 }
38
39 }
40 cnt = 0;
41 for(j = 1; j < N; ++j) {
42 cnt += dp[M][j];
43 }
44 d *= cnt;
45 }
46 printf("%.3f\n", tol - d);
47 }
48 return 0;
49 }
POJ 1840
a*i3 + b*j3 + c*k3 + d*l3 + e*l3 = 0;
a*i3 + b*j3 = - (d*l3 + e*l3+ c*k3 )
M + a*i3 + b*j3 = M - (d*l3 + e*l3+ c*k3) (M = 504*2)
hash开到M*2,注意用char型
POJ 2002
不知道为什么,按上下左右找出四对点来不对,按abs(pt.x + pt.y)存hash,然后按下左排序枚举出来的就对了,无语!!
POJ 2503
map蹭过去了,写ELFhash不是wa就是TLE...
POJ 3253
离散数学上的最优树问题,用堆写的Huffman算法,结果用long long,int会超的。
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <cmath>
5
6 using namespace std;
7
8 const int N = 20010;
9
10 int a[N];
11
12 void heap_adjust(int x, int n) {
13 int i, j, tmp;
14 i = x; j = i << 1;
15 tmp = a[x];
16 while(j <= n) {
17 if(j < n && a[j+1] < a[j]) ++j;
18 if(tmp > a[j]) {
19 a[i] = a[j];
20 i = j; j = i << 1;
21 }
22 else break;
23 }
24 a[i] = tmp;
25 }
26
27 int main() {
28 //freopen("data.in", "r", stdin);
29
30 int n, i;
31 long long tmp, ans;
32 while(~scanf("%d", &n)) {
33 for(i = 1; i <= n; ++i)
34 scanf("%d", a + i);
35 for(i = n/2; i >= 1; --i) heap_adjust(i, n);
36 ans = 0;
37 while(1) {
38 tmp = a[1]; a[1] = a[n--];
39 heap_adjust(1, n);
40
41 tmp += a[1]; a[1] = tmp;
42 heap_adjust(1, n);
43
44 ans += tmp;
45 if(n == 1) break;
46 }
47 printf("%lld\n", ans);
48 }
49 return 0;
50 }
POJ 2513
好久没写Trie树,这题是并查集+Trie树+判断是否存在两个以上的终点(度为奇数的点)
开始没考虑到多个终点的问题,贡献wa若干。。。
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <algorithm>
5
6 using namespace std;
7
8 const int N = 510000;
9
10 struct node {
11 int flag;
12 node *next[26];
13 node() {
14 flag = 0;
15 for(int i = 0; i < 26; ++i)
16 next[i] = NULL;
17 }
18 };
19
20 typedef struct node *Node;
21
22 int f[N], rank[N], deg[N], num;
23
24 int insert(Node &root, char *s) {
25 int n = strlen(s);
26 int i, t;
27 Node p = root;
28 for(i = 0; i < n; ++i) {
29 t = s[i] - 'a';
30 if(p->next[t] == NULL) {
31 p->next[t] = new node;
32 }
33 p = p->next[t];
34 }
35 if(p->flag == 0)
36 p->flag = num++;
37 return p->flag;
38 }
39
40 void del(Node &p) {
41 int i;
42 if(p) {
43 for(i = 0; i < 26; ++i) {
44 if(p->next[i])
45 del(p->next[i]);
46 }
47 }
48 delete p;
49 p = NULL;
50 }
51
52 void init() {
53 int i;
54 for(i = 0; i < N; ++i) f[i] = i, deg[i] = rank[i] = 0;
55 num = 1;
56 }
57
58 int find(int x) {
59 int k = x, j;
60 while(x != f[x]) x = f[x];
61 while(k != x) {
62 j = f[k];
63 f[k] = x;
64 k = j;
65 }
66 return x;
67 }
68
69
70 int main() {
71 //freopen("data.in", "r", stdin);
72
73 char s1[20], s2[20];
74 Node root;
75 int i, x, y, cnt;
76 init();
77 root = new node;
78 while(~scanf("%s %s", s1, s2)) {
79 x = insert(root, s1);
80 y = insert(root, s2);
81 //printf("%d %d\n", x, y);
82 deg[x]++; deg[y]++;
83 x = find(x); y = find(y);
84 if(x == y) continue;
85
86 if(rank[x] > rank[y]) f[y] = x;
87 else {
88 f[x] = y;
89 if(rank[x] == rank[y]) ++rank[y];
90 }
91 }
92 for(cnt = 0, i = 1; i < num; ++i) {
93 if(deg[i]%2) cnt++;
94 }
95 x = find(1);
96 for(i = 2; i < num; ++i) {
97 if(find(i) != x) {
98 puts("Impossible");
99 return 0;
100 }
101 }
102
103 if(cnt <= 3) puts("Possible");
104 else puts("Impossible");
105 del(root);
106 return 0;
107 }