Poj1480Eqs
a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0 ->a1x13+ a2x23+ a3x3=-(a4x43+ a5x53
问有多少个满足等式的非零x1,x2,x3,x4,x5组。)
中途相遇法,枚举x1,x2,x3得到左边式子的值插入hash表,然后枚举x4,x5找到对应的值就行了。
#include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #include <bitset> #include <queue> #include <stack> #include <string> #include <iostream> #include <cmath> #include <climits> typedef long long LL ; using namespace std; const int maxn = 1e6 + 7; const int Hash = 1e5 + 7; struct HashMap { int head[Hash + 10]; int size; int next[maxn*2]; int val[maxn*2]; int cnt[maxn*2]; void init() { size = 0; memset(head, -1, sizeof(head)); } int ask(int x) { int k = (x%Hash + Hash) % Hash; for (int i = head[k]; i != -1; i = next[i]){ if (val[i] == x) return cnt[i]; } return 0; } void insert(int x) { int k = (x%Hash + Hash) % Hash; for (int i = head[k]; i != -1; i = next[i]){ if (val[i] == x){ cnt[i] ++; return; } } val[size] = x; cnt[size] = 1; next[size] = head[k]; head[k] = size++; return; } }m; int gao(int i) { return i*i*i; } int main() { int a, b, c, d, e; while (cin>>a>>b>>c>>d>>e){ int ans = 0; m.init(); for (int i = -50; i <= 50; i++)if (i){ for (int j = -50; j <= 50; j++)if (j){ for (int k = -50; k <= 50; k++)if (k){ int t = a*gao(i) + b*gao(j)+c*gao(k); m.insert(t); } } } for (int i = -50; i <= 50; i++)if (i){ for (int j = -50; j <= 50; j++)if (j){ int t = d*gao(i) + e*gao(j); ans += m.ask(-t); } } cout << ans << endl; } return 0; }
Poj2549 Sumsets
题意:Given S, a set of integers, find the largest d such that a + b + c = d where a, b, c, and d are distinct elements of S.
还是用中途相遇法搞下就好了。
#include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #include <bitset> #include <queue> #include <stack> #include <string> #include <iostream> #include <cmath> #include <climits> typedef long long LL; using namespace std; const int Hash = 1e6 + 10; const int maxn = 1e6 + 10; struct HashMap { int head[Hash + 10]; int size; int next[maxn + 10]; int val[maxn + 10]; int a[maxn + 10], b[maxn + 10]; void init() { size = 0; memset(head, -1, sizeof(head)); } void insert(int t, int x, int y) { int k = (t%Hash + Hash) % Hash; for (int i = head[k]; i != -1; i = next[i]){ if (val[i] == t){ if (a[i] == x&&b[i] == y) return; } } val[size] = t; next[size] = head[k]; a[size] = x; b[size] = y; head[k] = size++; } int ask(int t, int x, int y) { int k = (t%Hash + Hash) % Hash; for (int i = head[k]; i != -1; i = next[i]){ if (val[i] == t){ if (a[i] != x&&b[i] != x&&a[i] != y&&b[i] != y) return 1; } } return 0; } }m; int cmp(const int &a, const int &b) { return a > b; } int a[1111]; int main() { int n; while (scanf("%d", &n) != EOF&&n){ for (int i = 0; i < n; i++){ scanf("%d", &a[i]); } m.init(); sort(a, a + n, cmp); for (int i = 0; i < n; i++){ for (int j = 0; j < n; j++){ if (i == j)continue; m.insert(a[i] + a[j], i, j); } } int flag = 1; int pos; for (int i = 0; flag&&i < n; i++){ for (int j = 0; flag&&j < n; j++){ if (i == j) continue; int t = m.ask(a[i] - a[j], i, j); if (t){ flag = 0; pos = i; break; } } } if (flag){ printf("no solution\n"); } else printf("%d\n", a[pos]); } return 0; }
Poj3274 Gold Balanced Lineup
就是给出一些数,找到最大的连续区间使得区间内对应的二进制位上的1的个数相等。
若区间l,r满足条件,sum[i][j] 表示前i个数的第j位上的1的个数和。
sum[r][1] - sum[l][1] = sum[r][2] - sum[l][2].....->sum[r][1] - sum[r][2] = sum[l][1] - sum[l][2];
每一位都减去某位的值过以后,若是存在l,r区间满足条件则处理过后的对应位的值相等,此时用hash搞下。
#include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #include <bitset> #include <queue> #include <stack> #include <string> #include <iostream> #include <cmath> #include <climits> typedef long long LL; using namespace std; const int Hash = 1e6 + 10; const int maxn = 2e5 + 10; int k; struct HashMap { int head[Hash + 10]; int next[maxn + 10]; int val[maxn + 10]; int ans[maxn + 10][31]; int pos[maxn + 10]; int size; void init() { size = 0; memset(head, -1, sizeof(head)); } int ask(int a[]) { int t = 0; for (int i = 0; i < k; i++) t += a[i]; int gg = (t%Hash + Hash) % Hash; for (int i = head[gg]; i != -1; i = next[i]){ if (val[i] == t){ int flag = 0; for (int j = 0; j < k; j++) { if (ans[i][j] != a[j]) { flag = 1; break; } } if (flag == 0) return pos[i]; } } return -2; } void insert(int a[], int p) { int t = 0; for (int i = 0; i < k; i++) t += a[i]; int gg = (t%Hash + Hash) % Hash;; for (int i = head[gg]; i != -1; i = next[i]){ if (val[i] == t){ int flag = 0; for (int j = 0; j < k; j++){ if (ans[i][j] != a[j]){ flag = 1; break; } } if (flag == 0) return; } } val[size] = t; next[size] = head[gg]; pos[size] = p; for (int i = 0; i < k; i++) ans[size][i] = a[i]; head[gg] = size++; } }m; int cnt[100]; void gao(int a) { int len = 0; while (a){ cnt[len++] += a % 2; a >>= 1; } } int main() { int n; int a; while (scanf("%d%d", &n, &k) != EOF){ int Max = 0; memset(cnt, 0, sizeof(cnt)); m.init(); m.insert(cnt, -1); for (int i = 0; i < n; i++){ scanf("%d", &a); gao(a); for (int j = k - 1; j >= 0; j--) cnt[j] -= cnt[0]; int t = m.ask(cnt); if (t != -2) Max = max(Max, i - t); m.insert(cnt, i); } printf("%d\n", Max); } return 0; }
Hdu3333 Turing Tree
区间长度3e4 ,1e5个询问。
给出区间,求区间内不同元素和的个数。
开始用莫队算法多了sqrt(n)的复杂度,超时了(或许姿势写戳了).后来搜了下题解,发现按照查询的右端点排序,然后线段树边插入,边查询就好了。
到第i个元素的时候,只保留i这个大小的数最后一次出现的位置,前面出现过的位置上的数置0。由于是按右端点排序,在到达第k条询问的右端点的时候,保证到了当前位置区间内所有重复的数只有一个。
#include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #include <bitset> #include <queue> #include <stack> #include <string> #include <iostream> #include <cmath> #include <climits> typedef long long LL; using namespace std; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const LL maxn = 33333; LL sum[maxn << 2]; LL last[maxn]; LL n; LL a[maxn]; LL b[maxn]; void build(LL l, LL r, LL rt) { sum[rt] = 0; if (l == r) return; LL mid = (l + r) >> 1; build(lson); build(rson); } void up(LL rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void update(LL pos, LL add, LL l, LL r, LL rt) { if (l == r){ sum[rt] = add; return; } LL mid = (l + r) >> 1; if (pos <= mid) update(pos, add, lson); else update(pos, add, rson); up(rt); } LL ask(LL L, LL R, LL l, LL r, LL rt) { if (L <= l&&r <= R) return sum[rt]; LL mid = (l + r) >> 1; LL ans = 0; if (L <= mid) ans += ask(L, R, lson); if (R>mid) ans += ask(L, R, rson); return ans; } void init() { vector<LL> q1; for (LL i = 0; i < n; i++) q1.push_back(a[i]); sort(q1.begin(), q1.end()); q1.erase(unique(q1.begin(), q1.end()), q1.end()); for (LL i = 0; i < n; i++) b[i] = lower_bound(q1.begin(), q1.end(), a[i]) - q1.begin(); } struct Node { LL l; LL r; LL id; }node[111111]; LL cmp(const Node &a1, const Node &b1) { return a1.r < b1.r; } LL ans[111111]; int main() { LL T; cin >> T; LL q; while (T--){ cin >> n; build(0, n - 1, 1); for (LL i = 0; i < n; i++){ scanf("%I64d", &a[i]); } init(); cin >> q; for (LL i = 0; i < q; i++){ scanf("%I64d%I64d", &node[i].l, &node[i].r); node[i].l -= 1; node[i].r -= 1; node[i].id = i; } memset(last, -1, sizeof(last)); sort(node, node + q, cmp); LL pos = 0; for (LL i = 0; i < q; i++){ while (pos <= node[i].r){ LL t = last[b[pos]]; if (t == -1){ update(pos, a[pos], 0, n - 1, 1); last[b[pos]] = pos; } else{ update(last[b[pos]], 0, 0, n - 1, 1); update(pos, a[pos], 0, n - 1, 1); last[b[pos]] = pos; } pos++; } ans[node[i].id] = ask(node[i].l, node[i].r, 0, n - 1, 1); } for (LL i = 0; i < q; i++){ printf("%I64d\n", ans[i]); } } return 0; }
Poj3188
题意:把L个字母按顺序分成连续的B份,变成手机按键,然后给出字典,问这些字典用手机按键去按,有多少个单词不存在冲突。
暴力枚举划分方式,然后hash去判断冲突。在弄的时候因为用了map,超时了,调了好久。。写的很戳
#include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #include <bitset> #include <queue> #include <stack> #include <string> #include <iostream> #include <cmath> #include <climits> typedef long long LL; using namespace std; const int Hash = 128; const int maxn = 1e6; int askval(char *s) { int k = 0; while (*s) k = (*s++) + (k << 6) + (k << 16) - k; return (k & 0x7fffffff); } int B, L, n; struct HashMap { int size; int head[Hash + 10]; int val[maxn + 10]; int next[maxn + 10]; char s[maxn][14]; int cnt[maxn + 10]; void init() { size = 0; memset(head, -1, sizeof(head)); } int ask(char *s1) { int k = askval(s1); int t = (k%Hash + Hash) % Hash; for (int i = head[t]; i != -1; i = next[i]){ if (val[i] == k){ if (strcmp(s1, s[i]) == 0) return cnt[i]; } } return 0; } void insert(char *s1) { int k = askval(s1); int t = (k%Hash + Hash) % Hash; for (int i = head[t]; i != -1; i = next[i]){ if (val[i] == k) if (strcmp(s1, s[i]) == 0){ cnt[i]++; return; } } val[size] = k; next[size] = head[t]; strcpy(s[size], s1); cnt[size] = 1; head[t] = size++; } }T; char str[1111][12]; int a[100]; int Max; int p[100]; int m[30]; void gao(int pos, int sum) { if (sum == B){ T.init(); memset(m, 0, sizeof(m)); for (int i = 0; i<B - 1; i++){ for (int j = a[i]; j<a[i + 1]; j++) m[j] = i; } for (int i = a[B - 1]; i<L; i++) m[i] = B - 1; int ans = 0; for (int i = 0; i<n; i++){ char s1[14]; strcpy(s1, str[i]); int len = strlen(s1); for (int j = 0; j<len; j++) s1[j] = m[s1[j] - ‘A‘] + ‘A‘; int t = T.ask(s1); if (!t) T.insert(s1), ans++; if (t == 1){ ans--; T.insert(s1); } } if (ans>Max){ Max = ans; for (int i = 0; i<B; i++) p[i] = a[i]; } return; } if (sum == 0){ a[sum] = 0; gao(0, sum + 1); } else for (int i = L - B + sum; i>pos; i--){ a[sum] = i; gao(i, sum + 1); } } int main() { while (scanf("%d%d", &B, &L) != EOF){ scanf("%d", &n); a[0] = -1; p[0] = -1; for (int i = 0; i < n; i++){ scanf("%s", str[i]); } Max = -1; gao(0, 0); printf("%d\n", Max); for (int i = 0; i<B - 1; i++){ for (int j = p[i]; j<p[i + 1]; j++) printf("%c", j + ‘A‘); printf("\n"); } for (int i = p[B - 1]; i<L; i++) printf("%c", i + ‘A‘); if (p[B - 1] <= L - 1) printf("\n"); } return 0; }