2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) Solution

A:Alphabet

Solved.

签。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 char s[60];
 4 int f[60];
 5 int main(){
 6     scanf("%s",s+1);
 7     int n=strlen(s+1);
 8     for(int i=1;i<=n;i++)
 9     {
10         f[i]=1;
11     }
12     for(int i=2;i<=n;i++)
13     {
14         for(int j=1;j<i;j++)
15         {
16             if(s[i]>s[j]){
17                 f[i]=max(f[i],f[j]+1);
18             }
19         }
20     }
21     int maxn=0;
22     for(int i=1;i<=n;i++)
23     {
24         maxn=max(maxn,f[i]);
25     }
26     cout<<26-maxn<<endl;
27 }
View Code

 

B:Buggy Robot

Solved.

题意:

给出一个地图,从'R' 走到 'E' , 可以增加或者删除机器人的指令

求最少的修改次数,使得机器人可以到达'E'

思路:

搜索。

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 const int maxn = 50 + 10;
  6 const int INF = 0x3f3f3f3f;
  7 
  8 struct node{
  9     int x, y;
 10     int step;
 11     node(){}
 12     node(int x, int y, int step): x(x), y(y), step(step){};
 13 };
 14 
 15 int n, m;
 16 int sx, sy, ex, ey;
 17 int len;
 18 char mp[maxn][maxn];
 19 char op[maxn * maxn];
 20 int dis[maxn][maxn][maxn * maxn];
 21 int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
 22 
 23 bool judge(int x,int y)
 24 {
 25     if(x < 1 || x > n || y < 1 || y > m || mp[x][y] == '#') return false;
 26     else return true;
 27 }
 28 
 29 void BFS()
 30 {
 31     queue<node>q;
 32     q.push(node(sx, sy, 0));
 33     dis[sx][sy][0] = 0;
 34     while(!q.empty())
 35     {
 36         node st = q.front();
 37         q.pop();
 38         //not do
 39         if(st.step + 1 <= len)
 40         {
 41             node now = st;
 42             now.step++;
 43             if(dis[st.x][st.y][st.step] + 1 < dis[now.x][now.y][now.step])
 44             {
 45                 dis[now.x][now.y][now.step] = dis[st.x][st.y][st.step] + 1;
 46                 q.push(now);
 47             }
 48         }
 49         //do
 50         if(st.step + 1 <= len)
 51         {
 52             node now = st;
 53             now.step++;
 54             if(op[now.step] == 'U')
 55             {
 56                 now.x--;
 57             }
 58             else if(op[now.step] == 'D')
 59             {
 60                 now.x++;
 61             }
 62             else if(op[now.step] == 'L')
 63             {
 64                 now.y--;
 65             }
 66             else if(op[now.step] == 'R')
 67             {
 68                 now.y++;
 69             }
 70             if(!judge(now.x, now.y))
 71             {
 72                 now.x = st.x;
 73                 now.y = st.y;
 74             }
 75             if(dis[st.x][st.y][st.step] < dis[now.x][now.y][now.step])
 76             {
 77                 dis[now.x][now.y][now.step] = dis[st.x][st.y][st.step];
 78                 q.push(now);
 79             }
 80 
 81         }
 82         //add
 83         node now = st;
 84         for(int i = 0; i < 4; ++i)
 85         {
 86             now.x = st.x + dir[i][0];
 87             now.y = st.y + dir[i][1];
 88             if(judge(now.x, now.y))
 89             {
 90                 if(dis[st.x][st.y][st.step] + 1 < dis[now.x][now.y][now.step])
 91                 {
 92                     dis[now.x][now.y][now.step] = dis[st.x][st.y][st.step] + 1;
 93                     q.push(now);
 94                 }
 95             }
 96         }
 97     }
 98 }
 99 
100 int main()
101 {
102     while(~scanf("%d %d", &n, &m))
103     {
104         for(int i = 1; i <= n; ++i)
105         {
106             for(int j = 1; j <= m; ++j)
107             {
108                 scanf(" %c", &mp[i][j]);
109                 if(mp[i][j] == 'R'){ sx = i, sy = j; }
110                 if(mp[i][j] == 'E'){ ex = i, ey = j; }
111             }
112         }
113         scanf("%s", op + 1);
114         len = strlen(op + 1);
115         memset(dis, 0x3f, sizeof dis);
116         BFS();
117         int ans = INF;
118         for(int i = 1; i <= len; ++i) ans = min(ans, dis[ex][ey][i]);
119         printf("%d\n", ans);
120     }    
121     return 0;
122 }
View Code

 

C:Cameras

Solved.

签。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 100010
 5 int n, k, r, a[N];
 6 
 7 int main()
 8 {
 9     while (scanf("%d%d%d", &n, &k, &r) != EOF)
10     {
11         memset(a, 0, sizeof a);
12         for (int i = 1, x; i <= k; ++i)
13         {
14             scanf("%d", &x);
15             a[x] = 1;
16         }    
17         int res = 0; 
18         int tot = 0;
19         for (int i = 1; i <= r - 1; ++i) tot += a[i]; 
20         for (int i = 1; i + r - 1<= n; ++i)
21         {
22             tot += a[i + r - 1];
23             if (tot < 2)
24             {
25                 for (int j = i + r - 1; j >= 1 && tot < 2; --j) if (!a[j])
26                 {
27                     a[j] = 1;
28                     ++tot;
29                     ++res;
30                 }
31             }
32             tot -= a[i];
33         }
34         printf("%d\n", res);
35     }
36     return 0; 
37 }
View Code

 

D:Contest Strategy

Unsolved.

题意:

在一场ICPC比赛中,有一个人知道它解决每道题需要多少时间

但是必须要先读这道题,才能做

做题策略是

开场先随机读k道题,然后按做题时间放入小根堆

每次取堆顶出来做,每做一道题,就随机再读一题(如果还有题目可以读)

求$\;N!\;种读题顺序的所有罚时加起来 MOD\;\; 1e\;9 +7$

 

 

E:Enclosure

Unsolved.

 

F:Illumination

Solved.

题意:

有一个矩形,在某些点有灯泡,可以选择照亮当前行或者照亮当前列

每个灯泡照亮的范围相同为$r$

但是同行或者同列的照亮不能相交

求有没有一种方案使得所有灯泡都可以打开

思路:

一个点拆成两个点,表示照亮行或列

然后建边,丢进2-sat跑一跑即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 2010
 5 int n, r, l;
 6 struct Graph
 7 {
 8     struct node
 9     {
10         int to, nx;
11         node () {}
12         node (int to, int nx) : to(to), nx(nx) {}
13     }a[N * N * 2];
14     int head[N], pos;
15     void init()
16     {
17         memset(head, -1, sizeof head);
18         pos = 0;
19     }
20     void add(int u, int v) { a[++pos] = node(v, head[u]); head[u] = pos; } 
21 }G;
22 #define erp(u) for (int it = G.head[u], v = G.a[it].to; ~it; it = G.a[it].nx, v = G.a[it].to)
23 int x[N], y[N];
24 // 0 x 1 y
25 
26 bool vis[N];
27 int S[N], top;
28 bool DFS(int u)
29 {
30     if (vis[u ^ 1]) return false;
31     if (vis[u]) return true;
32     vis[u] = 1;
33     S[top++] = u;
34     erp (u) if (!DFS(v)) return false;
35     return true;
36 }
37 
38 bool twosat(int n)
39 {
40     memset(vis, 0, sizeof vis);
41     for (int i = 0; i < n; i += 2)
42     {
43         if (vis[i] || vis[i ^ 1]) continue;
44         top = 0;
45         if (!DFS(i))
46         {
47             while (top) vis[S[--top]] = false;
48             if (!DFS(i ^ 1)) return false;
49         }
50     }
51     return true;
52 }
53 
54 int main()
55 {
56     while (scanf("%d%d%d", &n, &r, &l) != EOF)
57     {
58         G.init();
59         for (int i = 0; i < l; ++i) scanf("%d%d", x + i, y + i);
60         for (int i = 0; i < l; ++i) for (int j = i + 1; j < l; ++j)
61         {
62             if (x[i] == x[j] && abs(y[i] - y[j]) <= 2 * r)
63             {
64                 G.add(i << 1, j << 1 | 1);
65                 G.add(j << 1, i << 1 | 1);
66             }
67             if (y[i] == y[j] && abs(x[i] - x[j]) <= 2 * r)
68             {
69                 G.add(i << 1 | 1, j << 1);
70                 G.add(j << 1 | 1, i << 1);
71             }
72         }
73         puts(twosat(2 * l) ? "YES" : "NO");
74     }
75     return 0;
76 }
View Code
 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxn = 2e3 + 10;
 6 
 7 struct node{
 8     int x, y;
 9     node(){}
10     node(int x,int y): x(x), y(y){}
11 }arr[maxn];
12 
13 struct Edge{
14     int to, nxt;
15     Edge(){}
16     Edge(int to, int nxt) : to(to), nxt(nxt){}
17 }edge[(maxn * maxn) << 2];
18 
19 int head[maxn << 1], tot, vis[maxn << 1];
20 
21 void Init()
22 {
23     tot = 0;
24     memset(head, -1, sizeof head);
25     memset(vis, 0, sizeof vis);
26 }
27 
28 void addedge(int u, int v, int val)
29 {
30     int tmpu = u * 2 + val;
31     int tmpv = v * 2 + val;
32     edge[tot] = Edge(tmpv, head[tmpu ^ 1]); head[tmpu ^ 1] = tot++;
33     edge[tot] = Edge(tmpu, head[tmpv ^ 1]); head[tmpv ^ 1] = tot++;
34 }
35 
36 int n, r, l;
37 int S[maxn << 1], top;
38 
39 bool DFS(int u)
40 {
41     if(vis[u ^ 1]) return false;
42     if(vis[u]) return true;
43     vis[u]++;
44     S[top++] = u;
45     for(int i = head[u]; ~i; i = edge[i].nxt)
46     {
47         if(!DFS(edge[i].to)) return false;
48     }
49     return true;
50 }
51 
52 bool solve()
53 {
54     for(int i = 0; i < (l << 1); i += 2)
55     {
56         if(vis[i] == 0 && vis[i ^ 1] == 0)
57         {
58             top = 0;
59             if(!DFS(i))
60             {
61                 while(top) vis[S[--top]] = 0;
62                 if(!DFS(i ^ 1)) return false;
63             }    
64         }
65     }
66     return true;
67 
68 }
69 
70 int main()
71 {
72     while(~scanf("%d %d %d", &n, &r, &l))
73     {
74         Init();
75         for(int i = 0; i < l; ++i) scanf("%d %d", &arr[i].x, &arr[i].y);
76         for(int i = 0; i < l; ++i)
77         {
78             for(int j = 0; j < i; ++j)
79             {
80                 if(arr[i].y == arr[j].y && abs(arr[i].x - arr[j].x) <= 2 * r)
81                 {
82                     addedge(i, j, 0);
83                 }
84                 if(arr[i].x == arr[j].x && abs(arr[i].y - arr[j].y) <= 2 * r)
85                 {
86                     addedge(i, j, 1);
87                 }
88             }
89         }
90         puts(solve() ? "YES" : "NO");
91     }
92     return 0;
93 }
View Code

 

G:Maximum Islands

Unsolved.

题意:

有一张卫星图,可以看到陆地上有些地方是海洋,有些地方是陆地

陆地的连通块是岛屿,也有些地方看到的是云朵

云朵下面可以是陆地也可以是海洋

求岛屿的最大数量

 

H:Paint

Solved.

题意:

给出一些区间,求选出任意个数的区间,使得这些区间不相交

并且区间并最大,输出n - 区间并

思路:
类似于最长上升子序列,一个区间的左端点要接在所有右端点小于它的所有区间中的最大值即可

树状数组维护一下就没了

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 200010
 6 ll n, b[N << 2];
 7 int k, m; 
 8 struct qnode
 9 {
10     ll l, r;
11     void scan() { scanf("%lld%lld", &l, &r); }
12     bool operator < (const qnode &other) const { return r < other.r || r == other.r && l < other.l; }
13 }q[N];
14 
15 void Hash()
16 {
17     m = 0;
18     for (int i = 1; i <= k; ++i) 
19     {
20         b[++m] = q[i].l;
21         b[++m] = q[i].r;
22     }
23     sort(b + 1, b + 1 + m);
24     m = unique(b + 1, b + 1 + m) - b - 1;
25     for (int i = 1; i <= k; ++i)
26     {
27         q[i].l = lower_bound(b + 1, b + 1 + m, q[i].l) - b;
28         q[i].r = lower_bound(b + 1, b + 1 + m, q[i].r) - b;
29     }
30 }
31 
32 namespace BIT
33 {
34     ll a[N << 2];
35     void update(int x, ll val)
36     {
37         for (; x < (N << 2); x += x & -x)
38             a[x] = max(a[x], val);
39     }
40     ll query(int x)
41     {
42         ll res = 0;
43         for (; x; x -=x & -x)
44             res = max(res, a[x]);
45         return res;
46     }
47 }
48 
49 int main()
50 {
51     while (scanf("%lld%d", &n, &k) != EOF)
52     {
53         for (int i = 1; i <= k; ++i) q[i].scan(); Hash();
54         sort(q + 1, q + 1 + k); 
55         ll res = 0;
56         for (int i = 1; i <= k; ++i)
57         {
58             ll tmp = BIT::query(q[i].l - 1);
59             tmp += b[q[i].r] - b[q[i].l] + 1;
60             res = max(res, tmp);
61             BIT::update(q[i].r, tmp);
62         }
63         printf("%lld\n", n - res);
64     }
65     return 0;
66 }
View Code

 

I:Postman

Solved.

题意:

有n个房子,每个放在位于$x_i点$邮局在0点,每个房子有$m_i封信要送$

只有一个邮递员,每次最多携带$k_i封信,求邮递员最少的路程$

思路:

负的和正的分开做

每次都先跑最远的,如果可以携带多余的信,就给次远的,再给次次远的。

贪心做一下就没了

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 1010
 6 ll res; 
 7 int n, m, k; 
 8 int x[N], v[N];
 9 
10 struct node
11 {
12     int x, v;
13     node () {}
14     node (int x, int v) : x(x), v(v) {}
15     bool operator < (const node &r) const { return x < r.x; }
16 }q[N];
17 
18 void solve()
19 {
20     sort(q + 1, q + 1 + m);
21     for (int i = m; i >= 1; --i)
22     {
23         res += 2ll * (q[i].v / k) * q[i].x;
24         int remind = q[i].v % k;
25         if (remind) 
26         {
27             remind = k - remind;
28             res += 2ll * q[i].x;
29             for (int j = i - 1; j >= 1; --j) 
30             {
31                 if (remind >= q[j].v)
32                 {
33                     remind -= q[j].v;
34                     q[j].v = 0;
35                 }
36                 else
37                 {
38                     q[j].v -= remind;
39                     break;
40                 }
41             }
42         }
43     }
44 }
45 
46 int main()
47 {
48     while (scanf("%d%d", &n, &k) != EOF)
49     {
50         for (int i = 1; i <= n; ++i) scanf("%d%d", x + i, v + i); 
51         res = 0; m = 0;
52         for (int i = 1; i <= n; ++i) if (x[i] < 0) q[++m] = node(-x[i], v[i]);
53         solve();
54         m = 0;
55         for (int i = 1; i <= n; ++i) if (x[i] > 0) q[++m] = node(x[i], v[i]);
56         solve();
57         printf("%lld\n", res);    
58     }
59     return 0;
60 }
View Code

 

j:Shopping

Solved.

题意:

有一个超市,$有n种物品,每种物品a_i元,每种物品无限个$

$q次询问,每次询问从第l_i个商品走到第r_i个商品,身上有v_i块钱,能买则买,问最后剩下多少钱$

思路:

每次购买一个物品那么手中的钱至少缩小一半

最多需要购买log种物品

再二分查找最近的小于自己的物品

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 200010
 6 int n, q;
 7 ll a[N];
 8 
 9 ll dp[N][20];
10 int mm[N];
11 void init(int n, ll b[])
12 {
13     mm[0] = -1;
14     for (int i = 1; i <= n; ++i)
15     {
16         mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1: mm[i - 1];
17         dp[i][0] = b[i];
18     }
19     for (int j = 1; j <= mm[n]; ++j)
20         for (int i = 1; i + (1 << j) - 1 <= n; ++i)
21             dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
22 }
23 
24 ll query(int l, int r)
25 {
26     int k = mm[r - l + 1];
27     return min(dp[l][k], dp[r - (1 << k) + 1][k]);
28 }
29 
30 int main()
31 {
32     while (scanf("%d%d", &n, &q) != EOF)
33     {
34         for (int i = 1; i <= n; ++i) scanf("%lld", a + i); init(n, a); 
35         ll v;
36         for (int i = 1, l, r; i <= q; ++i)
37         {
38             scanf("%lld%d%d", &v, &l, &r);
39             while (r - l >= 0)
40             {
41                 int ql = l, qr = r, tar = -1;
42                 while (qr - ql >= 0)
43                 {
44                     int mid = (ql + qr) >> 1;
45                     if (query(ql, mid) <= v)
46                     {
47                         qr = mid - 1;
48                         tar = mid;
49                     }
50                     else
51                         ql = mid + 1;
52                 }
53                 if (tar == -1) break;
54                 v %= a[tar];
55                 l = tar + 1;
56             }
57             printf("%lld\n", v);
58         }
59     }
60     return 0;
61 }
View Code

 

K:Tournament Wins

Solved.

题意:

有$2^k个玩家,进行对局,rank小的一定能打败\;\;rank\;\;大的$

如果你$rank = r 那么求出你在一轮游戏中赢的局数的期望$

一轮游戏为每次两两对战,输的离开,赢得剩下继续对战,直到只有一个人

思路:

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = (1 << 20) + 10;
 5 const double EXP = exp(1.0);
 6 
 7 double fac[maxn];
 8 
 9 void Init()
10 {
11     fac[0] = 0;
12     for(int i = 1; i < maxn; ++i) fac[i] = fac[i - 1] + log(i);
13 }
14 
15 int k, r;
16 
17 int main()
18 {
19     Init();
20     while(~scanf("%d %d", &k, &r))
21     {
22         double ans = 0;
23         int limit = 1 << k;
24         for(int i = 1; i <= k; ++i)
25         {
26             int m = (1 << i);
27             if(limit - r - m + 1 < 0) break;
28             ans += exp((fac[limit - r] - fac[limit - r -  m + 1]) - (fac[limit - 1] - fac[limit - m]));
29         }
30         printf("%.5f\n", ans);
31     }
32     return 0;
33 }
View Code

 

L:Windy Path

Unsolved.

 

posted @ 2018-12-09 18:51  Dup4  阅读(588)  评论(0编辑  收藏  举报