2015 ACM/ICPC Asia Regional Hefei Online
2015-09-30 19:30
363 查看
A-Monitor the Alpacas(hdu 5484)
先给n个点,再给m个点,要从m个点中选出最少的点使得这m个点形成的凸包包含这n个点。因为m比较少,所以我们可以先对n个点求凸包,然后再判断m个点形成的线段是否和凸包相交。然后就得到了各个点可以相连的情况。于是再跑个最小环就是答案了。暴力点可以用floyd。
B-The Relationship in Club(hdu5485)
二分图染色计数。g(n)表示n个点任何满足的二分图有多少种可能。f(n)表示n个点形成联通的二分图的种数。然后求f(n)的时候,需要固定1点在X部。然后根据f(n)就可以同样固定1点在X部进行dp求解了。
详见_
C-Difference of Clustering(hdu 5486)
这题暴力左右两边枚举就可以了。需要用链表,开n个vector会MLE。
D-Difference of Languages(hdu 5487)
这题也是个暴力,因为两个DFA都只有1000个状态,所以从0 0状态开始广搜就可以了。需要注意的是,一个能走,另一个不能走也可能产生最短解。这个稍微处理一下就好了。
E-Shape
这题不会。
F-Removed Interval(hdu 5489)
这题我脑抽了,写了一个可持久化线段树。而且比赛的时候无线脑抽,导致上来就发现可以敲,然后一个多小时才过掉。这题只需要维护每个位置作为LIS开始位置的长度,然后可以用树状数组,线段树,可持久化线段树之类的简单数据结构维护一下每个值作为LIS最后一个位置的最长长度就好了。然后枚举到i的时候,就看看i-L-1之前比当前值小的LIS最大值就好了。
G-Simple Matrix(hdu 5490)
这题,对于位置i, j上的一个常数v来说,对n, m位置的答案贡献为 v * C(n - i + m - j, n - i),这个很显然。然后对于每一排的等比数列来说,计算到下一排仍然是等比数列+贡献一个常数。然后对于初始的等差数列,也可以根据常数贡献的方法去算。然后答案就很明显了。然后因为常数贡献的位置只有第一列和第二列,所以可以初始计算出一个组合数后,下面用递推式求出需要的组合数就好了。
H-The Next(hdu 5491)
据说是水题?
I-Find a path(hdu 5492)
把方差式子变换一下,然后把和作为状态暴力dp即可。
J-Queue(hdu 5493)
首先贪心,如果顺序放的话,对于每个数都可以确定出对称的两个位置,由于要字典序最小的。显然我们需要把这个数放在前面,然后就用线段树求一下每次要放的位置就好了。
先给n个点,再给m个点,要从m个点中选出最少的点使得这m个点形成的凸包包含这n个点。因为m比较少,所以我们可以先对n个点求凸包,然后再判断m个点形成的线段是否和凸包相交。然后就得到了各个点可以相连的情况。于是再跑个最小环就是答案了。暴力点可以用floyd。
B-The Relationship in Club(hdu5485)
二分图染色计数。g(n)表示n个点任何满足的二分图有多少种可能。f(n)表示n个点形成联通的二分图的种数。然后求f(n)的时候,需要固定1点在X部。然后根据f(n)就可以同样固定1点在X部进行dp求解了。
详见_
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #define LL long long #define MP make_pair #define xx first #define yy second #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1|1 #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 1111; const int MOD = 105225319; int g[maxn], f[maxn]; int dp[maxn]; int c[maxn][maxn], p2[maxn * maxn]; int n, m; void init() { p2[0] = 1; c[0][0] = 1; for(int i = 1; i < maxn; i ++) { c[i][0] = c[i][i] = 1; for(int j = 1; j < i; j ++) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD; } } int inv2 = (MOD + 1) / 2; void solve() { if(n == 1) { puts("0"); return ; } for(int i = 1; i <= n * n; i ++) p2[i] = 1ll * p2[i - 1] * (m + 1) % MOD; for(int i = 0; i <= n; i ++) { g[i] = 0; for(int j = 0; j <= i; j ++) g[i] = (g[i] + 1ll * c[i][j] * p2[j * (i - j)] % MOD) % MOD; } f[0] = 0; f[1] = 1; for(int i = 1; i <= n; i ++) { f[i] = 1ll * g[i] * inv2 % MOD; for(int j = 1; j <= i - 1; j ++) { f[i] = (f[i] + MOD - 1ll * c[i - 1][j - 1] * f[j] % MOD * g[i - j] % MOD) % MOD; } } CLR(dp, 0); dp[0] = 1; LL ans = 0; for(int i = 1; i <= n; i ++) { for(int j = 1; j <= i; j ++) dp[i] = (dp[i]+ 1ll * f[j] * c[i - 1][j - 1] % MOD * dp[i - j] % MOD) % MOD; } printf("%d\n", dp ); } int main() { init(); int T, cas = 1; scanf("%d", &T); while(T --) { scanf("%d%d", &n, &m); printf("Case #%d: ", cas ++); solve(); } return 0; }
C-Difference of Clustering(hdu 5486)
这题暴力左右两边枚举就可以了。需要用链表,开n个vector会MLE。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #define LL long long #define MP make_pair #define xx first #define yy second #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1|1 #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 1000010; map<int, int> x, y; int heada[maxn], headb[maxn]; int nexta[maxn], nextb[maxn]; int vala[maxn], valb[maxn]; int top1, top2; int sza, szb; int l[maxn]; int r[maxn]; int sizea[maxn], sizeb[maxn]; int vis[maxn]; vector<int> tmp; int main(){ int n, t, cas = 1; cin >> t; while(t --) { scanf("%d", &n); x.clear(); y.clear(); top1 = 0, top2 = 0; sza = szb = 0; for(int i = 0; i < n; i ++) { int u, v; scanf("%d%d", &u, &v); int tgt1, tgt2; if(x.count(u) == 0) { x[u] = tgt1 = top1; heada[top1] = -1; sizea[top1] = 0; top1 ++; }else{ tgt1 = x[u]; } nexta[sza] = heada[tgt1]; vala[sza] = i; heada[tgt1] = sza ++; sizea[tgt1] ++; l[i] = tgt1; if(y.count(v) == 0) { y[v] = tgt2 = top2; headb[top2] = -1; sizeb[top2] = 0; top2 ++; }else{ tgt2 = y[v]; } nextb[szb] = headb[tgt2]; valb[szb] = i; headb[tgt2] = szb ++; sizeb[tgt2] ++; r[i] = tgt2; } int ansSplits = 0, ansMerges = 0, ansOne = 0; for(int i = 0; i < top1; i ++) { int rad = rand(); tmp.clear(); for(int jj = heada[i]; ~jj; jj = nexta[jj]) { int id = vala[jj]; if(vis[r[id]] == rad) continue; tmp.push_back(r[id]); vis[r[id]] = rad; } if(tmp.size() > 1) { int sum = 0; for(int j = 0; j < tmp.size(); j ++) { sum += sizeb[tmp[j]]; } if(sum == sizea[i]) ansSplits ++; }else{ int sum = sizeb[tmp[0]]; if(sum == sizea[i]) ansOne ++; } } for(int i = 0; i < top2; i ++) { int rad = rand(); tmp.clear(); for(int jj = headb[i]; ~jj; jj = nextb[jj]) { int id = valb[jj]; if(vis[l[id]] == rad) continue; tmp.push_back(l[id]); vis[l[id]] = rad; } if(tmp.size() > 1) { int sum = 0; for(int j = 0; j < tmp.size(); j ++) { sum += sizea[tmp[j]]; } if(sum == sizeb[i]) ansMerges ++; } } printf("Case #%d: ", cas ++); printf("%d %d %d\n", ansSplits, ansMerges, ansOne); } return 0; }
D-Difference of Languages(hdu 5487)
这题也是个暴力,因为两个DFA都只有1000个状态,所以从0 0状态开始广搜就可以了。需要注意的是,一个能走,另一个不能走也可能产生最短解。这个稍微处理一下就好了。
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #define LL long long #define MP make_pair #define xx first #define yy second #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1|1 #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 1010; int dp[maxn][maxn]; pair<int, int> last[maxn][maxn]; int mp1[maxn][26], mp2[maxn][26]; bool ed1[maxn], ed2[maxn]; void dfs(int x, int y) { if(x == 0 && y == 0) return ; dfs(last[x][y].xx, last[x][y].yy); putchar(dp[x][y] + 'a'); } int n1, n2; void solve() { queue<pair<int, int> > Q; Q.push(MP(0, 0)); if(ed1[0] != ed2[0]) { puts(""); return ; } CLR(dp, -1); dp[0][0] = 27; while(!Q.empty()) { pair<int, int> u = Q.front(); Q.pop(); for(int i = 0; i < 26; i ++) { int vx = mp1[u.xx][i], vy = mp2[u.yy][i]; if(vx == -1 && vy == -1) continue; if(vx == -1) vx = n1; if(vy == -1) vy = n2; if(dp[vx][vy] != -1) continue; dp[vx][vy] = i; last[vx][vy] = u; if(ed1[vx] != ed2[vy]) { dfs(vx, vy); putchar('\n'); return ; } Q.push(MP(vx, vy)); } } puts("0"); } int main() { int T, cas = 1; scanf("%d", &T); while(T --) { int n, m, k; CLR(mp1, -1); CLR(ed1, false); scanf("%d%d%d", &n, &m, &k); n1 = n; for(int i = 0; i < k; i ++) { int u; scanf("%d", &u); ed1[u] = true; } for(int i = 0; i < m; i ++) { int u, v; char o[4]; scanf("%d%d%s", &u, &v, o); mp1[u][o[0] - 'a'] = v; } CLR(mp2, -1); CLR(ed2, false); scanf("%d%d%d", &n, &m, &k); n2 = n; for(int i = 0; i < k; i ++) { int u; scanf("%d", &u); ed2[u] = true; } for(int i = 0; i < m; i ++) { int u, v; char o[4]; scanf("%d%d%s", &u, &v, o); mp2[u][o[0] - 'a'] = v; } printf("Case #%d: ", cas ++); solve(); } return 0; }
E-Shape
这题不会。
F-Removed Interval(hdu 5489)
这题我脑抽了,写了一个可持久化线段树。而且比赛的时候无线脑抽,导致上来就发现可以敲,然后一个多小时才过掉。这题只需要维护每个位置作为LIS开始位置的长度,然后可以用树状数组,线段树,可持久化线段树之类的简单数据结构维护一下每个值作为LIS最后一个位置的最长长度就好了。然后枚举到i的时候,就看看i-L-1之前比当前值小的LIS最大值就好了。
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #define LL long long #define MP make_pair #define xx first #define yy second //#define lson l, m, rt << 1 //#define rson m + 1, r, rt << 1|1 #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 100100; const int maxm = 20*maxn; int n, L, m, tot; int a[maxn], t[maxn]; int T[maxm], lson[maxm], rson[maxm], c[maxm]; void init_Hash() { for(int i = 1; i <= n; i ++) t[i] = a[i]; sort(t + 1, t + 1 + n); m = unique(t + 1, t + n + 1) - t - 1; } int build(int l, int r) { int root = tot ++; c[root] = 0; if(l != r) { int mid = (l + r) >> 1; lson[root] = build(l, mid); rson[root] = build(mid + 1, r); } return root; } int Hash(int x) { return lower_bound(t + 1, t + m + 1, x) - t; } void up(int rt) { c[rt] = max(c[lson[rt]], c[rson[rt]]); } int query(int rt, int L, int R, int l, int r) { if(L <= l && r <= R) { return c[rt]; } int m = (l + r) >> 1; int ret = 0; if(L <= m) ret = max(ret, query(lson[rt], L, R, l, m)); if(R > m) ret = max(ret, query(rson[rt], L, R, m + 1, r)); return ret; } int update(int rt, int pos, int val, int l, int r) { int root = tot ++; if(l == r) { c[root] = val; return root; } int m = (l + r) >> 1; lson[root] = lson[rt]; rson[root] = rson[rt]; if(pos <= m) lson[root] = update(lson[rt], pos, val, l, m); else rson[root] = update(rson[rt], pos, val, m + 1, r); up(root); return root; } int b[maxn], o[maxn]; #define INF 0x3f3f3f3f void gao() { CLR(o, INF); for(int i = n; i > 0; i --) { int tmp = lower_bound(o + 1, o + n + 1, b[i]) - o; o[tmp] = b[i]; b[i] = tmp; } } int main() { int cas = 1, Tt; scanf("%d", &Tt); while(Tt --) { tot = 0; scanf("%d%d", &n, &L); for(int i = 1; i <= n; i ++) { scanf("%d", &a[i]); } init_Hash(); T[0] = build(1, m); for(int i = 1; i <= n; i ++) { int pos = Hash(a[i]); a[i] = pos; b[i] = m + 1 - pos; int val = 0; if(pos > 1) val = query(T[i - 1], 1, pos - 1, 1, m); T[i] = update(T[i - 1], pos, val + 1, 1, m); } gao(); int ans = query(T[n - L], 1, m, 1, m); for(int i = L + 1; i <= n; i ++) { int tmp = 0; if(a[i] > 1) tmp = query(T[i - L - 1], 1, a[i] - 1, 1, m); ans = max(ans, tmp + b[i]); } printf("Case #%d: %d\n", cas ++, ans); } return 0; }
G-Simple Matrix(hdu 5490)
这题,对于位置i, j上的一个常数v来说,对n, m位置的答案贡献为 v * C(n - i + m - j, n - i),这个很显然。然后对于每一排的等比数列来说,计算到下一排仍然是等比数列+贡献一个常数。然后对于初始的等差数列,也可以根据常数贡献的方法去算。然后答案就很明显了。然后因为常数贡献的位置只有第一列和第二列,所以可以初始计算出一个组合数后,下面用递推式求出需要的组合数就好了。
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #define LL long long #define MP make_pair #define xx first #define yy second #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1|1 #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 10100; const int MOD = 1000000007; LL Powmod(LL a, int n) { LL ret = 1; a = (a + MOD) % MOD; while(n) { if(n & 1) ret = ret * a % MOD; a = a * a % MOD; n >>= 1; } return ret; } int a, d, b, q, n, m; LL C(LL n, int m) { LL ret = 1; for(int i = 0; i < m; i ++) { ret = ret * (n - i) % MOD * Powmod(i + 1, MOD - 2) % MOD; } return ret; } void solve() { LL ans = 0; if(n == 0) { if(m == 0) { puts("0"); return ; } ans = 1ll * b * Powmod(q, m - 1) % MOD; printf("%I64d\n", ans); return ; } if(m == 0) { ans = a + 1ll * d * (n - 1) % MOD; printf("%I64d\n", ans % MOD); return ; } if(q==0) { LL x = C(n + m - 2, n - 1); ans = x * b % MOD; b = 0; q = 1; } LL X = C(n + m - 1, n - 1); int bb = b, qq = Powmod(q - 1, MOD - 2); for(int i = 1; i <= n; i ++) { LL tmp = 1ll * b * qq % MOD; LL Y = Powmod(n + m - i, MOD - 2); tmp = tmp * X % MOD * Y % MOD * m % MOD; b = 1ll * b * q % MOD * qq% MOD; ans = (ans + a * X % MOD) % MOD; ans = (ans + MOD - tmp) % MOD; X = X * (n - i) % MOD * Y % MOD; a = d; } if(q == 1) { X = C(n + m - 1, n); ans = (ans + X * bb % MOD) % MOD; printf("%I64d\n", ans); return ; } ans = (ans + b * Powmod(q, m - 1) % MOD) % MOD; printf("%I64d\n", ans); } int main() { int T, cas = 1; scanf("%d", &T); while(T --) { scanf("%d%d%d%d%d%d", &b, &q, &a, &d, &n, &m); printf("Case #%d: ", cas ++); solve(); } return 0; }
H-The Next(hdu 5491)
据说是水题?
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #define LL long long #define MP make_pair #define xx first #define yy second #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1|1 #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn=111111; int s[maxn]; int main(){ int t, cas = 1; LL d; int s1, s2; cin >> t; while(t --) { scanf("%I64d%d%d", &d, &s1, &s2); int now = 0; int cnt = 0; while(d) { if(d&1)s[now] = 1, cnt ++; else s[now] = 0; now ++; d >>= 1; } s[now] = 0; if(cnt != s2) { int pos = -1; for(int i = 0; i <= now; i ++) { if(s[i] == 0) { cnt ++; pos = i; s[i] = 1; break; } } for(int i = pos; i <= now; i ++) { if(s[i] == 1) s1 --; } int tmp = max(0, s1); for(int i = 0; i < pos; i ++) { if(tmp) s[i] = 1, tmp --; else s[i] = 0; } }else{ int pos = -1; bool ok = false; for(int i = 0; i <= now; i ++) { if(s[i] == 0 && ok) { cnt ++; pos = i; s[i] = 1; break; } if(s[i] == 1) { ok = true; } } for(int i = pos; i <= now; i ++) { if(s[i] == 1) s1 --; } int tmp = max(0, s1); for(int i = 0; i < pos; i ++) { if(tmp) s[i] = 1, tmp --; else s[i] = 0; } } LL ans = 0; for(int i = now; i >= 0; i --) { ans = (ans << 1) | s[i]; } printf("Case #%d: ", cas ++); printf("%I64d\n", ans); } return 0; }
I-Find a path(hdu 5492)
把方差式子变换一下,然后把和作为状态暴力dp即可。
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #define LL long long #define MP make_pair #define xx first #define yy second #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1|1 #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 35; const int inf = 0x3f3f3f3f; int s[maxn][maxn]; int dp[maxn][maxn][60*30*2]; int main(){ int t, cas = 1, n, m; cin >> t; while(t --) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) { for(int j = 1; j <= m; j ++) { scanf("%d", &s[i][j]); } } memset(dp, inf, sizeof dp); dp[1][1][s[1][1]] = s[1][1] * s[1][1]; for(int i = 1; i <= n; i ++) { for(int j = 1; j <= m; j ++) { for(int k = 0; k <= 1800; k ++) { if(dp[i][j][k] == inf) continue; dp[i][j + 1][k + s[i][j + 1]] = min(dp[i][j + 1][k + s[i][j + 1]], dp[i][j][k] + s[i][j + 1] * s[i][j + 1]); dp[i + 1][j][k + s[i + 1][j]] = min(dp[i + 1][j][k + s[i + 1][j]], dp[i][j][k] + s[i + 1][j] * s[i + 1][j]); } } } LL ans = inf; for(int i = 0; i <= 1800; i ++) { ans = min(ans, (n + m - 1ll) * dp [m][i] - i * i); } printf("Case #%d: ", cas ++); printf("%I64d\n", ans); } return 0; }
J-Queue(hdu 5493)
首先贪心,如果顺序放的话,对于每个数都可以确定出对称的两个位置,由于要字典序最小的。显然我们需要把这个数放在前面,然后就用线段树求一下每次要放的位置就好了。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #define LL long long #define MP make_pair #define xx first #define yy second #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1|1 #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 100100; int sum[maxn<<2]; int n; void PushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void build(int l = 1, int r = n, int rt = 1) { if(l == r) { sum[rt] = 0; return ; } int m=(l + r) >> 1; build(lson); build(rson); PushUp(rt); } void update(int p, int l = 1, int r = n, int rt = 1) { if(l == r) { sum[rt] = 1; return ; } int m = (l + r) >> 1; if (p <= m) update(p, lson); else update(p ,rson); PushUp(rt); } int query(int p, int l = 1, int r = n, int rt = 1) { if(l == r) { return l; } int m = (l + r) >> 1; int lsz = m - l + 1 - sum[rt << 1]; if (lsz >= p) return query(p , lson); return query(p - lsz, rson); } int a[maxn], r[maxn], b[maxn], ans[maxn]; bool cmp(int i, int j) { return a[i] < a[j]; } void solve() { sort(b + 1, b + n + 1, cmp); int tot = n; build(); for(int i = 1; i <= n; i ++) { int id = b[i]; int p = min(r[id] + 1, tot - r[id]); if(p <= 0) { puts("impossible"); return ; } int pos = query(p); ans[pos] = a[id]; update(pos); tot --; } for(int i = 1; i <= n; i ++) printf("%d%c", ans[i], i == n ? '\n' : ' '); } int main() { int T, cas = 1; scanf("%d", &T); while(T --) { scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("%d%d", &a[i], &r[i]); b[i] = i; } printf("Case #%d: ", cas ++); solve(); } return 0; }
相关文章推荐
- 2014武大邀请赛总结
- 【比赛总结】2014 Multi-University Training Contest 1
- 【比赛总结】2014 Multi-University Training Contest 9
- The 14th Zhejiang University Programming Contest
- Ural Championship 2012
- The 11th Zhejiang Provincial Collegiate Programming Contest
- 福州大学第十一届程序设计竞赛
- 北京师范大学第十二届程序设计竞赛
- 2013 成都邀请赛
- 2014 北京、西安邀请赛
- 2014东北四省赛
- 2013 Asia Regional Changchun 解题报告
- 2015年百度之星程序设计大赛 - 初赛(1)
- BNU Training 2015.08.17
- ACM-ICPC国际大学生程序设计竞赛北京赛区(2015)网络赛
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 理工校赛决赛赛后总结
- NYOJ 370 波动序列 dp 动态规划
- CDZSC_2014上半年组队赛(1)
- CDZSC_2014上半年组队赛(2)