2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)
题解:链接
Tournament Wins
题意: 2^k个人,你排名第r, 问你能赢的期望次数.
至少赢 i 次的概率是 C(2^i-1, 2^k-r) / C(2^i-1, 2^k-1) ,化简一下

1 #include <bits/stdc++.h> 2 using namespace std; 3 int k, r; 4 5 int main() { 6 scanf("%d %d", &k, &r); 7 int m = (1<<k) - r; 8 double ans = 0; 9 int i; 10 for(i = 1; (1<<i)-1 <= m; i++){ 11 double p = 1.0; 12 // int a = (1<<k) - (1<<i) + 2 - r; 13 //int c = (1<<k) - r + 1; 14 int a = (1<<k) - 1; 15 int c = (1<<k) - r; 16 for(int j = 0; j <(1<<i)-1 ; j++) { 17 p = p*c/a; 18 a--; 19 c--; 20 } 21 ans += p; 22 } 23 printf("%.5lf ", ans); 24 }
Maximum Islands
题意: 给一个卫星图, 有陆地, 海洋和未知区域, 问最多有多少个陆地四连块.
首先明确已知的陆地周围必须都是海洋, 然后未知区域单独为陆地的情况下四连块才会最多.
黑白染色,求二分图最大独立集.
又是二分图匹配....感觉自己好菜哇=_=

1 #include <bits/stdc++.h> 2 #define CLR(m, a) memset(m, a, sizeof(m)) 3 using namespace std; 4 const int maxn = 1610; 5 6 struct Edge{ 7 int v, nex; 8 Edge(int v=0, int nex=0) : v(v), nex(nex) {} 9 }e[maxn<<2]; 10 int head[maxn]; 11 int cnt; 12 13 void init(){ 14 CLR(head,-1); 15 cnt = 0; 16 } 17 void add(int u, int v) { 18 e[cnt] = Edge(v, head[u]) ; 19 head[u] = cnt++ ; 20 } 21 22 char p[42][42]; 23 int vis[42][42]; 24 25 int n, m; 26 int dir[4][2] = {0,1,0,-1,1,0,-1,0}; 27 void dfs(int x, int y){ 28 vis[x][y] = 1; 29 for(int i = 0; i < 4; i++){ 30 int dx = x + dir[i][0]; 31 int dy = y + dir[i][1]; 32 if(dx>=0&&dx<n&&dy>=0&&dy<m&&!vis[dx][dy]) { 33 if(p[dx][dy] == 'L') dfs(dx,dy); 34 if(p[dx][dy] == 'C') p[dx][dy] = 'W'; 35 } 36 } 37 } 38 39 int vb[maxn], vg[maxn], mcb[maxn]; 40 41 int Hungary(int u){ 42 vg[u] = 1; 43 for(int i = head[u]; ~i; i = e[i].nex){ 44 int v = e[i].v; 45 if(!vb[v]){ 46 vb[v] = 1; 47 if(mcb[v] == -1 || Hungary(mcb[v])) { 48 mcb[v] = u; 49 return 1; 50 } 51 } 52 } 53 return 0; 54 } 55 56 int main(){ 57 // freopen("in.txt", "r", stdin); 58 while(scanf("%d %d", &n, &m)!= EOF) { 59 init(); 60 for(int i = 0; i < n; i++) scanf("%s", p[i]); 61 int tot = 0; 62 CLR(vis, 0); 63 for(int i = 0; i < n; i++){ 64 for(int j = 0; j < m; j++){ 65 if(p[i][j] == 'L'&& !vis[i][j]) { 66 dfs(i,j); 67 tot++; 68 } 69 } 70 } 71 CLR(vis, 0); 72 int N = 0; 73 for(int i = 0; i < n; i++) 74 for(int j = 0; j < m; j++) 75 if(p[i][j]=='C') vis[i][j] = ++N; 76 77 for(int i = 0; i < n; i++) { 78 for(int j = 0; j < m; j++) { 79 if((i+j)%2==0 && vis[i][j]) { 80 for(int k = 0; k < 4; k++) { 81 int dx = i+dir[k][0]; 82 int dy = j+dir[k][1]; 83 if(dx>=0 && dx<n && dy>=0 && dy<m && vis[dx][dy]) add(vis[i][j], vis[dx][dy]); 84 } 85 } 86 } 87 } 88 int ans = 0; 89 CLR(mcb, -1); 90 for(int i = 0; i < n; i++) 91 for(int j = 0; j < m; j++) 92 if(vis[i][j] && (i+j)%2 == 0) { 93 CLR(vg, 0); 94 CLR(vb, 0); 95 if(Hungary(vis[i][j])) ans++; 96 } 97 printf("%d ", N - ans + tot); 98 } 99 }
Alphabet
求最长上升子序列.

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 55; 4 char s[maxn]; 5 int d[maxn]; 6 int main() { 7 //freopen("in.txt", "r", stdin); 8 while(scanf("%s", s) != EOF) { 9 int n = strlen(s); 10 int ans = 0; 11 memset(d, 0, sizeof(d)); 12 for(int i = 0; i < n; i++) { 13 for(int j = 0; j < i; j++) { 14 if(s[j] < s[i]) d[i] = max(d[i], d[j]+1); 15 ans = max(ans, d[i]); 16 } 17 } 18 printf("%d ", 25 - ans); 19 } 20 }
Cameras
暴力也能过,有点慢900+ms

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 100010; 5 6 int vis[maxn]; 7 int n, k, r; 8 9 int main(){ 10 // freopen("in.txt", "r", stdin); 11 while(scanf("%d %d %d", &n, &k, &r) != EOF) { 12 memset(vis, 0, sizeof(vis)); 13 for(int i = 0; i < k; i++) { 14 int x; 15 scanf("%d", &x); 16 vis[x] = 1; 17 } 18 int res = 0; 19 for(int i = 1; i+r-1 <= n; i++) { 20 int cnt = 0; 21 for(int j = i; j <= r+i-1; j++){ 22 if(vis[j]) cnt++; 23 if(cnt==2) break; 24 } 25 int id = r+i-1; 26 while(cnt<2) { 27 while(vis[id]) id--; 28 vis[id] = 1; 29 cnt++; 30 res++; 31 // printf("---%d ", id); 32 } 33 } 34 printf("%d ", res); 35 } 36 }
其实可以用树状数组维护下区间和~ 30ms

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 100010; 5 6 int c[maxn], vis[maxn]; 7 int n, k, r; 8 9 int lowbit(int x) { 10 return x&(-x); 11 } 12 void add(int x, int d){ 13 while(x <= n) { 14 c[x] += d; 15 x += lowbit(x); 16 } 17 } 18 19 int sum(int x) { 20 int ans = 0; 21 while(x > 0) { 22 ans += c[x]; 23 x -= lowbit(x); 24 } 25 return ans; 26 } 27 28 int main(){ 29 //freopen("in.txt", "r", stdin); 30 while(scanf("%d %d %d", &n, &k, &r) != EOF) { 31 memset(c, 0, sizeof(c)); 32 memset(vis, 0, sizeof(vis)); 33 for(int i = 0; i < k; i++) { 34 int x; 35 scanf("%d", &x); 36 vis[x] = 1; 37 add(x, 1); 38 } 39 int res = 0; 40 for(int i = 1; i+r-1 <= n; i++) { 41 int cnt = sum(r+i-1) - sum(i-1); 42 int id = r+i-1; 43 while(cnt<2) { 44 while(vis[id]) id--; 45 add(id, 1); 46 vis[id] = 1; 47 cnt++; 48 res++; 49 } 50 } 51 printf("%d ", res); 52 } 53 }
Shopping
Gym - 101201J题意:n件商品,k个人,每个人m元钱,从L走到R,每遇到一件商品就尽可能的多买,问最后剩余多少钱~
二分查找当前区间内小于m的最前位置

1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 5 const int maxn = 200010; 6 7 ll a[maxn]; 8 ll dp[maxn][30]; 9 10 void rmq_init(int n) { 11 for(int i = 1; i <= n; i++) dp[i][0] = a[i]; 12 int k = 0; 13 while(1<<(k+1) <= n+1) k++; 14 for(int i = 1; i <= k; i++) { 15 for(int j = 0; j + (1<<i) -1 <= n; j++) { 16 dp[j][i] = min(dp[j][i-1], dp[j+(1<<i-1)][i-1]); 17 } 18 } 19 } 20 21 ll rmq(int L, int R) { 22 int k = 0; 23 while(1<<(k+1) <= R-L+1) k++; 24 return min(dp[L][k], dp[R-(1<<k)+1][k]); 25 } 26 27 int main(){ 28 int n, k; 29 //freopen("in.txt", "r", stdin); 30 scanf("%d %d", &n, &k) ; 31 for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); 32 rmq_init(n); 33 while(k--) { 34 ll m; 35 int p, q; 36 scanf("%lld %d %d", &m, &p, &q); 37 while(1){ 38 int L = p, R = q; 39 while(L <= R) { 40 int M = (L + R) >> 1; 41 if(rmq(L,M) <= m) R = M-1; 42 else L = M+1; 43 // cout<<L<<" "<<R<<endl; 44 } 45 if(L > q) { 46 printf("%lld ", m); 47 break; 48 } 49 // printf("%d %lld--- ", L, a[L]); 50 p = L+1; 51 m %= a[L]; 52 if(m==0) { 53 printf("%lld ", m); 54 break; 55 } 56 } 57 } 58 59 return 0; 60 }