2014 multi-school cooperation 4 (HDU 4901 HDU 4902 HDU 4905), hdu4902
HDU 4901 The Romantic Hero
Question: a string of numbers a finds a separate position. The first part is "S" followed by "T". The subsets S and T are selected respectively from the two sets so that the "exclusive" value of the elements in "S" is equal to "T ". there are several solutions to ask the "and" value of an element
Ideas:
Since a [I] only has 1024, no matter how it is computed, it cannot be greater than 2047. Because S and T have an obvious division, we can think of using the dp to process both sides to make l [I] [j] indicates the number of solutions with an exclusive or j value when a [I] is selected from left to I. r [I] [j] similar to sl [I] [j] indicates l [1 ~ I] [j] AND sr [I] [j] can be obtained through positive and negative scanning. Finally, to prevent repeated counting, you can use sl [I] [j] * r [I + 1] [j] Or sr [I] [j] * l [I-1] [j] to update the answer
Code:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 1010#define mod 1000000007#define M 2048int l[N][M], r[N][M], sl[N][M], sr[N][M], a[N];int t, n, ans;int main() {int i, j, v;scanf("%d", &t);while (t--) {scanf("%d", &n);for (i = 1; i <= n; i++)scanf("%d", &a[i]);memset(l, 0, sizeof(l));memset(sl, 0, sizeof(sl));l[1][a[1]] = sl[1][a[1]] = 1;for (i = 2; i <= n; i++) {for (j = 0; j < M; j++) {v = j ^ a[i];l[i][v] = sl[i - 1][j];}l[i][a[i]] = (l[i][a[i]] + 1) % mod;for (j = 0; j < M; j++)sl[i][j] = (sl[i - 1][j] + l[i][j]) % mod;}memset(r, 0, sizeof(r));memset(sr, 0, sizeof(sr));r[n][a[n]] = sr[n][a[n]] = 1;for (i = n - 1; i >= 1; i--) {for (j = 0; j < M; j++) {v = j & a[i];r[i][v] = (r[i][v] + sr[i + 1][j]) % mod;}r[i][a[i]] = (r[i][a[i]] + 1) % mod;for (j = 0; j < M; j++)sr[i][j] = (sr[i + 1][j] + r[i][j]) % mod;}ans = 0;for (i = 1; i < n; i++) {for (j = 0; j < M; j++) {if (sl[i][j] && r[i + 1][j]) {ans = ((__int64 ) sl[i][j] * r[i + 1][j] % mod + ans) % mod;}}}printf("%d\n", ans);}return 0;}
HDU 4902 Nice boat
N numbers m operations 1 operation changes all values in the [l, r] interval to x 2 Operation 2 Operation changes [l, r] Replace the number larger than x with the gcd value of x.
Idea: it is obvious that the line segment tree does not think of how to merge two operations for a certain interval. Think about how to update it to the leaf node (here the leaves refer to the same number for a continuous interval) I felt that the line segment tree could not be optimized, so I started to play brute force. The result would be over 500 ms...
The brute-force method is simple because if operation 1 overwrites the point f, then all operations before operation 1 are meaningless. Therefore, the brute-force enumeration of n locations is not applicable to scanning operations from the back to the front of each location. one operation is break, and then the scan's 2 operations can be performed again to simulate the stack.
Code:
#include<cstdio>#include<algorithm>using namespace std;__int64 last[100010], a[100010], num[100010];int l[100010], r[100010], op[100010];int n, m, t;__int64 func(__int64 fa) {if (fa < 0)return -fa;return fa;}__int64 kgcd(__int64 fa, __int64 fb) {if (fa == 0)return fb;if (fb == 0)return fa;if (!(fa & 1) && !(fb & 1))return kgcd(fa >> 1, fb >> 1) << 1;else if (!(fb & 1))return kgcd(fa, fb >> 1);else if (!(fa & 1))return kgcd(fa >> 1, fb);elsereturn kgcd(func(fa - fb), min(fa, fb));}int main() {int i, j, top;__int64 ans;scanf("%d", &t);for (; t; t--) {scanf("%d", &n);for (i = 1; i <= n; i++)scanf("%I64d", &a[i]);scanf("%d", &m);for (i = 1; i <= m; i++)scanf("%d%d%d%I64d", &op[i], &l[i], &r[i], &num[i]);for (i = 1; i <= n; i++) {top = 0;ans = a[i];for (j = m; j >= 1; j--) {if (i >= l[j] && i <= r[j]) {if (op[j] == 1) {ans = num[j];break;} else {last[++top] = num[j];}}}for (j = top; j > 0; j--) {if (ans > last[j])ans = kgcd(ans, last[j]);}printf("%I64d ", ans);}putchar('\n');}return 0;}
HDU 4905 The Little dedevil II
No more questions about quadrilateral Optimization
Note: Do not be superstitious about the speed gcd. My teammates have been using it for several times. Why? Is the algorithm incorrect? No... It is expected that gcd will be faster and better, but the gcd of this question is a gcd of all numbers in a range. Because the numbers are random, it is easy to generate small numbers, so it is still reliable.
Code:
#include<cstdio>#include<cstring>#include<algorithm>typedef __int64 ll;using namespace std;const int M = 3010;int a[M], s[M][M], g[M][M];ll dp[M][M];int n;template<class T>inline void scan_d(T &ret) {char c;ret = 0;while ((c = getchar()) < '0' || c > '9');while (c >= '0' && c <= '9')ret = ret * 10 + (c - '0'), c = getchar();}inline int abs(int a) {return a < 0 ? -a : a;}int gcd(int a, int b) {if (a < b)swap(a, b);int i;while (b) {i = a % b;a = b;b = i;}return a;}inline void solve() {int l, i, j, k;memset(dp, 0, sizeof(dp));for (i = 1; i <= n; i++)s[i][i] = i;for (l = 1; l <= n - 1; l++) {for (i = 1; i <= n - l; i++) {j = i + l;for (k = s[i][j - 1]; k <= s[i + 1][j]; k++) {if (k < j && dp[i][j] < dp[i][k] + dp[k + 1][j] + g[i][j]) {dp[i][j] = dp[i][k] + dp[k + 1][j] + g[i][j];s[i][j] = k;}}}}}int main() {int min, i, j;int T;scan_d(T);while (T--) {scan_d(n);ll max = 0;ll s = 0;for (i = 1; i <= n; i++) {scan_d(a[i]);s += a[i];}for (i = 1; i <= n; i++) {g[i][i] = a[i];for (j = i + 1; j <= n; j++) {g[i][j] = gcd(g[i][j - 1], a[j]);}}solve();printf("%I64d\n", s + dp[1][n]);}return 0;}
PS: During the competition, the brain is still not very clever. TAT is always able to think deeply when someone else asks questions... Sad... At the same time, team cooperation must be strengthened !! Come on !!