2016 Multi-University Training Contest 4
2016-07-31 15:24
597 查看
天天不知道忙些什么,懒得博客都不贴了。
其实我真的想花大量时间好好学英语。
A
题意:给定两个串a和b,你可以选择在串a中把与b相同的子串替换成∗。问你可以得到多少种不同的新串。
思路:先kmp,记录所有与b相等的子串的区间[l,r],然后做dp。
dp[i][0]表示处理前i个且第i个区间不选用。
dp[i][1]表示处理前i个且选用第i个区间。
E
题意:给定n个a[i],p[i],问你在区间[l,r]里面可以被7整除的数里面有多少个满足对任意一个i均有%a[i]!=p[i]。
MDZZ,过了后缀数组那道,看看过题数,瞬间感觉被欺骗了。
思路:这就是一个很裸的斥 + CRT的题目。
我们做过类似 给你n个数,问区间[l,r]有多少个数满足不被这n个数任意一个整除,这和上面是一样的,只不过多了个被7整除。我们每次容斥的时候把%7==0加上,CRT的时候会爆long long,中间套个二进制优化乘法即可。
F
题意:问你包含字符x的不同子串个数。
一开始想歪了,MDZZ。其实是一道裸后缀数组,我们二分找到距离每个后缀最近的x字符的位置,然后统计每个后缀的贡献即可。
J
题意:你可以把元素中的0改成任意整数,问你可以得到的LIS。
思路:0全部用上一定最优,那考虑0的个数对非0元素处理一下,跑一发LIS。
K
求字符串出现次数,不说了。
L
题意:问你冒泡排序过程中元素出现的最左位置和最右位置的绝对值。
思路:发现若i后有num比它小的元素,那么它一定会向右移动num个位置。之后肯定是回到i位置了。
最右位置r=pos[i]+num(比它小的元素个数)。
最左位置 = min(pos[i],i)。
其实我真的想花大量时间好好学英语。
A
题意:给定两个串a和b,你可以选择在串a中把与b相同的子串替换成∗。问你可以得到多少种不同的新串。
思路:先kmp,记录所有与b相等的子串的区间[l,r],然后做dp。
dp[i][0]表示处理前i个且第i个区间不选用。
dp[i][1]表示处理前i个且选用第i个区间。
#include <cstdio> #include <algorithm> #include <iostream> #include <cmath> #include <vector> #include <cstring> #include <queue> #include <map> #include <set> #include <string> #define CLR(a, b) memset(a, (b), sizeof(a)) #define ll o<<1 #define rr o<<1|1 using namespace std; typedef long long LL; typedef pair<int, int> pii; const int MAXN = 1e5 + 10; const int MAXM = 1e5 + 1; const int INF = 1e9 + 10; const int MOD = 1e9 + 7; void add(LL &x, LL y) {x += y; x %= MOD;} int s[MAXN]; LL dp[MAXN][2]; int len1, len2, top; char s1[MAXN], s2[MAXN]; int nextn[MAXN]; void makenext() { int j = -1, i = 0; nextn[i] = j; while(i < len1) { if(j == -1 || s1[i] == s1[j]) { i++; j++; nextn[i] = j; } else { j = nextn[j]; } } } void kmp() { int i = 0, j = 0; makenext(); while(i < len2) { if(j == -1 || s2[i] == s1[j]) { i++; j++; if(j == len1) { s[++top] = i-len1; } } else { j = nextn[j]; } } } int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { scanf("%s%s", s2, s1); len1 = strlen(s1); len2 = strlen(s2); top = 0; kmp(); CLR(dp, 0); dp[0][0] = 1LL; dp[0][1] = 0; for(int i = 1; i <= top; i++) { if(i == 1) { dp[i][0] = dp[i][1] = 1LL; } else { add(dp[i][1], dp[i-1][0] + dp[i-1][1]); if(s[i] - s[i-1] + 1 <= len1) { int j = lower_bound(s + 1, s + i - 1, s[i] - len1 + 1) - s - 1; add(dp[i][0], dp[j][0] + dp[j][1]); } else { add(dp[i][0], dp[i-1][0] + dp[i-1][1]); } } } LL ans = 0; add(ans, dp[top][0] + dp[top][1]); printf("Case #%d: %lld\n", kcase++, ans); } return 0; }
E
题意:给定n个a[i],p[i],问你在区间[l,r]里面可以被7整除的数里面有多少个满足对任意一个i均有%a[i]!=p[i]。
MDZZ,过了后缀数组那道,看看过题数,瞬间感觉被欺骗了。
思路:这就是一个很裸的斥 + CRT的题目。
我们做过类似 给你n个数,问区间[l,r]有多少个数满足不被这n个数任意一个整除,这和上面是一样的,只不过多了个被7整除。我们每次容斥的时候把%7==0加上,CRT的时候会爆long long,中间套个二进制优化乘法即可。
#include <cstdio> #include <algorithm> #include <iostream> #include <cmath> #include <vector> #include <cstring> #include <queue> #include <map> #include <set> #include <string> #define CLR(a, b) memset(a, (b), sizeof(a)) #define ll o<<1 #define rr o<<1|1 using namespace std; typedef long long LL; typedef pair<int, int> pii; const int MAXN = 1e5 + 10; const int MAXM = 1e5 + 1; const int INF = 1e9 + 10; const int MOD = 1e9 + 7; void add(LL &x, LL y) {x += y; x %= MOD;} LL multi(LL a, LL b, LL m){ LL ans = 0; while(b) { if(b & 1LL) { ans = (ans + a) % m; } a = (a << 1) % m; b >>= 1; } return ans; } LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); } void exgcd(LL a, LL b, LL &d, LL &x, LL &y) { if(b == 0) {d = a, x = 1, y = 0;} else { exgcd(b, a % b, d, y, x); y -= x * (a / b); } } LL M; LL CRT(LL l, LL r, LL *m, LL *a) { M = 1; LL d, y, x = 0; for(LL i = l; i <= r; i++) { M = M / gcd(M, m[i]) * m[i]; } for(LL i = l; i <= r; i++) { LL w = M / m[i]; exgcd(m[i], w, d, d, y); x = (x + multi(multi(y, w, M), a[i], M)) % M; } return (x + M) % M; } LL Count(LL ans, LL N) { if(ans > N) return 0; else { return (N - ans) / M + 1; } } LL a[20], p[20]; LL x[20], y[20], k; int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { int n; LL l, r; scanf("%d%lld%lld", &n, &l, &r); for(int i = 0; i < n; i++) { scanf("%lld%lld", &a[i], &p[i]); } x[0] = 7, y[0] = 0; LL ans = 0; for(int i = 0; i < (1 << n); i++) { int cnt = 0; k = 1; for(int j = 0; j < n; j++) { if(i & (1 << j)) { x[k] = a[j]; y[k++] = p[j]; cnt++; } } LL temp = CRT(0, k - 1, x, y); LL res = Count(temp, r) - Count(temp, l - 1); if(cnt & 1) { ans -= res; } else { ans += res; } } printf("Case #%d: %lld\n", kcase++, ans); } return 0; }
F
题意:问你包含字符x的不同子串个数。
一开始想歪了,MDZZ。其实是一道裸后缀数组,我们二分找到距离每个后缀最近的x字符的位置,然后统计每个后缀的贡献即可。
#include <cstdio> #include <algorithm> #include <cmath> #include <vector> #include <cstring> #include <queue> #include <map> #include <set> #include <string> #define CLR(a, b) memset(a, (b), sizeof(a)) #define ll o<<1 #define rr o<<1|1 using namespace std; typedef long long LL; typedef pair<int, int> pii; const int MAXN = 1e5 + 10; const int MAXM = 1e5 + 1; const int INF = 1e9 + 10; const int MOD = 1e9 + 7; void add(LL &x, LL y) {x += y; x %= MOD;} int cmp(int *r, int a, int b, int l) { return (r[a] == r[b]) && (r[a+l] == r[b+l]); } int wa[MAXN], wb[MAXN], ws[MAXN], wv[MAXN]; int R[MAXN]; int H[MAXN]; void DA(int *r, int *sa, int n, int m) { int i, j, p, *x = wa, *y = wb, *t; for(i = 0; i < m; i++) ws[i] = 0; for(i = 0; i < n; i++) ws[x[i]=r[i]]++; for(i = 1; i < m; i++) ws[i] += ws[i-1]; for(i = n-1; i >= 0; i--) sa[--ws[x[i]]] = i; for(j = 1, p = 1; p < n; j *= 2, m = p) { for(p = 0, i = n-j; i < n; i++) y[p++] = i; for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j; for(i = 0; i < n; i++) wv[i] = x[y[i]]; for(i = 0; i < m; i++) ws[i] = 0; for(i = 0; i < n; i++) ws[wv[i]]++; for(i = 1; i < m; i++) ws[i] += ws[i-1]; for(i = n-1; i >= 0; i--) sa[--ws[wv[i]]] = y[i]; for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++) x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++; } } void calh(int *r, int *sa, int n) { int i, j, k = 0; for(i = 1; i <= n; i++) R[sa[i]] = i; for(i = 0; i < n; H[R[i++]] = k) for(k ? k-- : 0, j = sa[R[i]-1]; r[i+k] == r[j+k]; k++); } int sa[MAXN]; int a[MAXN], id[MAXN]; char str[MAXN]; vector<int> pos; int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { char op[2]; scanf("%s%s", op, str); int n = strlen(str); int Max = 0; pos.clear(); for(int i = 0; i < n; i++) { a[i] = str[i]; Max = max(Max, a[i]); if(str[i] == op[0]) { pos.push_back(i); } } a = 0; DA(a, sa, n+1, Max+1); calh(a, sa, n); for(int i = 0; i < n; i++) { int p = lower_bound(pos.begin(), pos.end(), i) - pos.begin(); if(p == pos.size()) { id[i] = -1; } else { id[i] = pos[p]; } } LL ans = 0; for(int i = 1; i <= n; i++) { if(id[sa[i]] == -1) continue; if(i == 1) ans += n - id[sa[i]]; else { ans += n - max(H[i] + sa[i], id[sa[i]]); } } printf("Case #%d: %lld\n", kcase++, ans); } return 0; }
J
题意:你可以把元素中的0改成任意整数,问你可以得到的LIS。
思路:0全部用上一定最优,那考虑0的个数对非0元素处理一下,跑一发LIS。
#include <cstdio> #include <algorithm> #include <iostream> #include <cmath> #include <vector> #include <cstring> #include <queue> #include <map> #include <set> #include <string> #define CLR(a, b) memset(a, (b), sizeof(a)) #define ll o<<1 #define rr o<<1|1 using namespace std; typedef long long LL; typedef pair<int, int> pii; const int MAXN = 1e5 + 10; const int MAXM = 1e5 + 1; const int INF = 1e9 + 10; const int MOD = 1e9 + 7; void add(LL &x, LL y) {x += y; x %= MOD;} int g[MAXN], a[MAXN], b[MAXN], dp[MAXN]; int pre[MAXN]; int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { int n; scanf("%d", &n); int top = 0; int cnt = 0, sum = 0; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); if(a[i] != 0) { pre[++top] = cnt; b[top] = a[i]; g[top] = INF; dp[top] = 1; cnt = 0; } else { sum++; cnt++; } } int ans = 0; for(int i = 1; i <= top; i++) { int k = lower_bound(g + 1, g + top + 1, b[i] - pre[i]) - g; dp[i] = k; ans = max(ans, dp[i]); g[dp[i]] = min(g[dp[i]], b[i] - pre[i]); } printf("Case #%d: %d\n", kcase++, ans + sum); } return 0; }
K
求字符串出现次数,不说了。
L
题意:问你冒泡排序过程中元素出现的最左位置和最右位置的绝对值。
思路:发现若i后有num比它小的元素,那么它一定会向右移动num个位置。之后肯定是回到i位置了。
最右位置r=pos[i]+num(比它小的元素个数)。
最左位置 = min(pos[i],i)。
#include <cstdio> #include <algorithm> #include <iostream> #include <cmath> #include <vector> #include <cstring> #include <queue> #include <map> #include <set> #include <string> #define CLR(a, b) memset(a, (b), sizeof(a)) #define ll o<<1 #define rr o<<1|1 using namespace std; typedef long long LL; typedef pair<int, int> pii; const int MAXN = 1e5 + 10; const int MAXM = 1e5 + 1; const int INF = 1e9 + 10; const int MOD = 1e9 + 7; void add(LL &x, LL y) {x += y; x %= MOD;} pii a[MAXN]; int lowbit(int x) { return x & (-x); } int n; int C[MAXN]; void add(int x) { while(x <= n) { C[x]++; x += lowbit(x); } } int Sum(int x) { int s = 0; while(x > 0) { s += C[x]; x -= lowbit(x); } return s; } int num[MAXN], pos[MAXN]; int main() { int t, kcase = 1; scanf("%d", &t); while(t--) { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i].first); a[i].second = i; pos[a[i].first] = i; } sort(a + 1, a + n + 1); CLR(C, 0); for(int i = 1; i <= n; i++) { num[a[i].first] = Sum(n) - Sum(a[i].second); add(a[i].second); } printf("Case #%d:", kcase++); for(int i = 1; i <= n; i++) { //cout << num[i] << endl; int r = pos[i] + num[i]; int l = min(i, pos[i]); printf(" %d", r - l); } printf("\n"); } return 0; }
相关文章推荐
- 2016 Multi-University Training Contest 3 solutions BY 绍兴一中
- 2016 Multi-University Training Contest 10 solutions BY BUPT
- 2016 Multi-University Training Contest 7 1010 Joint Stacks (模拟)
- HDU5723 2016 Multi-University Training Contest 1 (最小生成树+dfs)
- 2016 Multi-University Training Contest 1 1002 Chess (博弈+状态压缩)
- 2016 Multi-University Training Contest 1 1006 PowMod
- 2016 Multi-University Training Contest 2 Acperience
- 2016 Multi-University Training Contest 2 1001 Acperience
- 【HDU】5734 Acperience(2016 Multi-University Training Contest 2)
- 2016 Multi-University Training Contest 2 1009 It's All In The Mind (贪心)
- hdu 5734 Acperience(2016 Multi-University Training Contest 2——化简公式,数学推导)
- 【HDU5726 2016 Multi-University Training Contest 1D】【gcd的下降性质 STL-map】GCD 多少段区间gcd等于给定区间gcd
- HDU-2016 Multi-University Training Contest 3-Sqrt Bo-大数开方
- 2016 Multi-University Training Contest 2 总结
- 2016 Multi-University Training Contest 3 Rower Bo
- 2016 Multi-University Training Contest 3----解题报告
- 【HDU5739 2016 Multi-University Training Contest 2F】【cdq分治+并查集做法 or 点双连通做法】Fantasia 每点删除后联通块权值和的积
- 2016 Multi-University Training Contest 4 1012 hdu 5775(树状数组)
- 2016 Multi-University Training Contest 4 1001 Another Meaning
- 2016 Multi-University Training Contest 3 解题报告