2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2) 【部分题解】

A:由于删除是不计入操做次数的,因此转化一下就是求最长上升子序列,简单dp。node

     设dp[i]表示前i个字符能凑成上升子序列的最大长度,dp[i] = max(dp[j]+1, dp[i]) 【j < i && s[j] < s[i]】ios

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = 1e6+5;
12 
13 string s;
14 int dp[105];
15 
16 int main()
17 {
18     //FIN;
19     cin >> s;
20     int len = s.size(), maxn = 0;
21     rep(i, 1, len){
22         dp[i] = 1;
23         rep(j, 1, i-1){
24             if(s[j-1] < s[i-1]) dp[i] = max(dp[j]+1, dp[i]);
25         }
26         maxn = max(maxn, dp[i]);
27     }
28     cout << 26-maxn << endl;
29     return 0;
30 }
View Code

 

B:能够看出题目其实就是让你求有多少对哑铃片,每一片哑铃只能用一次且这一对重量相同。c++

     最多只可能有14个哑铃片,所以咱们能够用二进制进行枚举,假设二进制是 101011(高->低),那么表示1,2,4,6号哑铃片被选中了;数组

     这样的话最多 2^14种重量,接下来咱们只须要判断一下相同重量的方案是否是知足每种哑铃片只用了一次。ide

     eg: 假设 1001和1100构成的重量是相同的,可是它们都选择了4号哑铃片,因此这种状况是不知足题意的,只有 1001和 0110这种状况知足;spa

     可见判断标准就是看两个方案的二进制数的按位与操做的结果是否是0,是的话表示知足,不是的话表示有重复使用,则不知足。3d

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = (1<<16);
12 
13 int n, m;
14 LL a[20], b[20];
15 vector <LL> ans, ANS;
16 map <LL, bool> vis, VIS;
17 struct Node{
18     int bt;
19     LL val;
20     bool operator < (const Node &r) const   { return val < r.val; }
21 }node[N];
22 
23 bool judge(int i, int j){
24     int a = node[i].bt, b = node[j].bt;
25     if(a&b) return false;
26     return true;
27 }
28 int main()
29 {IO;
30     //FIN;
31     cin >> n >> m;
32     rep(i, 1, n)    cin >> a[i];
33     rep(i, 1, m)    cin >> b[i];
34 
35     rep(i, 0, ((1<<m)-1)){
36         int bit = i, p = 1;
37         LL res = 0;
38         while(bit){
39             if(bit&1)   res += b[p];
40             p++; bit >>= 1;
41         }
42         node[i].val = res;
43         node[i].bt = i;
44     }
45     sort(node, node+(1<<m));
46     int i = 0;
47     while(i < (1<<m)){
48         int j = i+1;
49         if(vis[node[i].val])    { i++; continue; }
50         while(j < (1<<m)){
51             if(node[i].val != node[j].val)  break;
52             if(judge(i, j)){
53                 if(!vis[node[i].val]) ans.pb(node[i].val);
54                 vis[node[i].val] = true;
55             }
56             j++;
57         }
58         i++;
59     }
60     //rep(i, 0, (int)ans.size()-1)    cout << ans[i] << " ";
61     rep(i, 1, n){
62         if(!VIS[a[i]])  ANS.pb(a[i]);
63         VIS[a[i]] = true;
64         rep(j, 0, (int)ans.size()-1){
65             LL res = a[i]+ans[j]*2;
66             if(!VIS[res]) ANS.pb(res);
67             VIS[res] = true;
68         }
69     }
70     sort(ANS.begin(), ANS.end());
71     rep(i, 0, (int)ANS.size()-1)    cout << ANS[i] << endl;
72     return 0;
73 }
View Code

 

C:貌似还没补。。。。。。code

D:这是一道贪心题,咱们能够从左往右贪心。假设当前位置是pos,那么咱们能够看一下pos往右的长度为r的区间内有几个摄像机,blog

     若是大于2,那么不须要放,不然须要放1个或2个。咱们为了使摄像机充分利用,那么咱们尽量把摄像机给右边放,也就是说,队列

     咱们从 pos+r-1 的位置往左扫,碰到没有摄像机的位置给它放就好了,知道 [pos, pos+r-1]这个区间的摄像机很多于2个就好。

     快速判断 [pos, pos+r-1]的摄像机个数,有的位置标记1,没有的标记0,那么区间求和就是摄像机个数;

     快速求区间和操做能够看看树状数组,固然能够用前缀和以及特殊的处理也能够搞定这个题。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = 1e5+5;
12 
13 LL n, k, r, x, c[N];
14 bool vis[N];
15 
16 int lowbit(int x)   { return x&-x; }
17 void add(int id, int p){
18     while(id <= n){
19         c[id] += p;
20         id += lowbit(id);
21     }
22 }
23 LL sum(int id){
24     LL ans = 0;
25     while(id >= 1){
26         ans += c[id];
27         id -= lowbit(id);
28     }
29     return ans;
30 }
31 int main()
32 {IO;
33     //FIN;
34     cin >> n >> k >> r;
35     rep(i, 1, k)    { cin >> x; vis[x] = true; add(x, 1); }
36     LL ans = 0;
37     rep(i, 1, n-r+1){
38         LL res = sum(i+r-1)-sum(i-1);
39         if(res < 2){
40             per(j, i+r-1, i){
41                 if(res >= 2) break;
42                 if(!vis[j]){
43                     add(j, 1);
44                     vis[j] = true;
45                     ans++;
46                     res++;
47                 }
48             }
49         }
50     }
51     cout << ans << endl;
52     return 0;
53 }
View Code

 

E:按照题意,咱们每次是从长度为k的序列中找罚时最小的来处理的,那么只须要用个优先队列,每次把最小的pop出来,而后按照题意进行模拟就好了。

     关于优先队列的用法请出门右拐百度 "STL 优先队列"

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = 1e6+5;
12 
13 int n, k, a[305];
14 priority_queue<int, vector<int>, greater<int> > Q;
15 
16 int main()
17 {
18     //FIN;
19     cin >> n >> k;
20     rep(i, 1, n)    cin >> a[i];
21     LL ans = 0, pre = 0, tol = 0;
22     rep(i, 1, k)    Q.push(a[i]);
23 
24     int id = k+1;
25     while(!Q.empty()){
26         ans = pre+Q.top(); Q.pop();
27         pre = ans;
28         tol += ans;
29         if(id <= n) { Q.push(a[id]); id++; }
30     }
31     cout << tol << endl;
32     return 0;
33 }
View Code

 


F:签到题,判断a + b = c,处理读入能够简化操做。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = 1e6+5;
12 
13 int a, b, c;
14 
15 int main()
16 {
17     scanf("%d + %d = %d", &a, &b, &c);
18     if(a+b == c)    printf("YES\n");
19     else printf("NO\n");
20     return 0;
21 }
View Code

 

G:苹果下落,按照题意模拟就好了。把每一个苹果往下掉,直到不能掉为止。注意有坑点,有可能上下是多个苹果相连,

     那么若是判断条件不合理的话,最后结果只是最底下的一层掉落了。所以咱们能够从下往上模拟就不会出现这个问题了。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = 1e6+5;
12 
13 int n, m, G[55][55];
14 string s;
15 
16 int main()
17 {
18     //FIN;
19     cin >> n >> m;
20     rep(i, 1, n){
21         cin >> s;
22         rep(j, 0, m-1){
23             if(s[j] == 'o') G[i][j+1] = 0;
24             if(s[j] == '#') G[i][j+1] = -1;
25             if(s[j] == '.') G[i][j+1] = 1;
26         }
27     }
28     per(i, n, 1){
29         rep(j, 1, m){
30             if(G[i][j] == 0){
31                 int id = i+1;
32                 while(id <= n && G[id][j] == 1) id++;
33                 swap(G[i][j], G[id-1][j]);
34             }
35         }
36     }
37     rep(i, 1, n){
38         rep(j, 1, m){
39             if(G[i][j] == 0)    cout << 'o';
40             if(G[i][j] == 1)    cout << '.';
41             if(G[i][j] == -1)   cout << '#';
42         }
43         cout << endl;
44     }
45     return 0;
46 }
View Code

 

H:题意是让你求L的联通块个数,C能够表明L或者W。这是个简单的搜索题,试想一下,若是我当前有个位置是L,那么我确定这个联通块是存在的,

     那么往下搜索碰到C时,我若是把C当成L处理,对于我最后联通块的数目是只可能减小,不可能增长的。由于刚开始已是一个L往下搜索,确定是有一个联通块了,

     碰到C的,我能够吧 LCL这种连在一块儿,所以只减不增。

     使用到的技巧:能够每次dfs完了以后把通过的点变成W,这样之后就不用再走了。注意第同样例这种特殊判断的状况。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = 1e6+5;
12 
13 int n, m, res, G[55][55], dir[4][2] = {0,1,0,-1,1,0,-1,0};
14 string s;
15 
16 bool judge(int x, int y){
17     if(x < 1 || x > n || y < 1 || y > m || G[x][y] == -1)    return false;
18     return true;
19 }
20 void dfs(int x, int y){
21     rep(i, 0, 3){
22         int xi = x+dir[i][0], yi = y+dir[i][1];
23         if(judge(xi, yi)){
24             G[xi][yi] = -1;
25             dfs(xi, yi);
26         }
27     }
28     return ;
29 }
30 int main()
31 {
32     //FIN;
33     cin >> n >> m;
34     rep(i, 1, n){
35         cin >> s;
36         rep(j, 0, m-1){
37             if(s[j] == 'C') G[i][j+1] = 0;
38             if(s[j] == 'W') G[i][j+1] = -1;
39             if(s[j] == 'L') G[i][j+1] = 1;
40         }
41     }
42     int ans = 0;
43     rep(i, 1, n){
44         rep(j, 1, m){
45             if(G[i][j] == 1){
46                 ans++;
47                 dfs(i, j);
48             }
49         }
50     }
51     cout << ans << endl;
52     return 0;
53 }
View Code

 

I: 咱们贪心的想一下,就能够发现,我能配对多少对袜子是和个人maxn和tol有关的。

     若是 tol/2 >= maxn,结果就是 tol/2, 不然的话结果就是 tol-maxn;具体能够多试几组数据画一画理解一下。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = (1<<16);
12 
13 int n;
14 LL x;
15 
16 int main()
17 {IO;
18     //FIN;
19     cin >> n;
20     LL tol = 0, maxn = 0;
21     rep(i, 1, n)    { cin >> x; maxn = max(maxn, x); tol += x; }
22     cout << (tol >= maxn*2 ? tol/2 : tol-maxn) << endl;
23     return 0;
24 }
View Code

 

J:这也是一道贪心题,咱们须要把位置大于0和小于0分开处理。对于每种状况,由于咱们一趟所带的信封是固定的,

    因此咱们确定是想要把最远的位置跑的趟数尽量少,那么只须要从远及近派送信封便可,每次送完信封还有剩余的时候,咱们能够把它送给下一个位置。

    这样正负两种状况都处理一下就能够解决了。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = (1<<16);
12 
13 int n;
14 LL k;
15 
16 struct Node{
17     int pos;
18     LL c;
19     bool operator < (const Node &r) const   { return pos < r.pos; }
20 }node[1005];
21 
22 int main()
23 {IO;
24     //FIN;
25     cin >> n >> k;
26     rep(i, 1, n)    cin >> node[i].pos >> node[i].c;
27     sort(node+1, node+n+1);
28     LL ans = 0, res = 0;
29     int i = n;
30     while(i >= 1){
31         if(node[i].pos < 0) break;
32         LL cnt = (node[i].c+k-1)/k;
33         ans += node[i].pos*cnt;
34         LL sum = cnt*k;
35         while(i >= 1 && sum && node[i].pos >= 0){
36             if(node[i].c <= sum)    { sum -= node[i].c; i--; }
37             else { node[i].c -= sum; break; }
38         }
39     }
40     i = 1;
41     while(i <= n){
42         if(node[i].pos >= 0) break;
43         LL cnt = (node[i].c+k-1)/k;
44         ans -= node[i].pos*cnt;
45         LL sum = k*cnt;
46         while(i <= n && sum && node[i].pos < 0){
47             if(node[i].c <= sum)    { sum -= node[i].c; i++; }
48             else { node[i].c -= sum; break; }
49         }
50     }
51     cout << ans*2 << endl;
52     return 0;
53 }
View Code

 

K:掷骰子判断a赢的几率,总共只有6*6=36种状况,最后的结果 ans = a赢 / (36 - 平局);高中简单几率计算题

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = 1e6+5;
12 
13 int a[10], b[10];
14 
15 int main()
16 {
17     //FIN;
18     rep(i, 1, 6)    cin >> a[i];
19     rep(i, 1, 6)    cin >> b[i];
20     double cnt1 = 0, cnt2 = 0;
21     rep(i, 1, 6){
22         rep(j, 1, 6){
23             if(a[i] > b[j]) cnt1++;
24             if(a[i] == b[j])    cnt2++;
25         }
26     }
27     printf("%.5lf\n", cnt1*1.0/(36-cnt2));
28     return 0;
29 }
View Code

 

L:能够知道,只有三种矩形,那么不管怎么拼,其中的最长边才有多是最后正方形的边长的,基于这一点,能够分类讨论一下。

 1 #include<bits/stdc++.h>
 2 #define  IO ios_base::sync_with_stadio(0);cin.tie(0);
 3 using namespace std;
 4 int a[55][55];
 5 int main()
 6 {
 7     int a1, b1, a2, b2, a3, b3;
 8     while(cin >> a1 >> b1 >> a2 >> b2 >> a3 >> b3){
 9         int a = max(a1, b1);
10         int b = max(a2, b2);
11         int c = max(a3, b3);
12         int d = a, flag = 1;
13         if(b > d){d = b; flag = 2;}
14         if(c > d){d = c; flag = 3;}
15         if(flag == 1){
16             int e = a2 + a3;
17             int f = a2 + b3;
18             int g = b2 + a3;
19             int h = b2 + b3;
20             if(e == d){
21                 if(b2 == b3 && (b2 + a1 == d || b2 + b1 == d)){ cout << "YES" << endl; continue;}
22             }
23             if(f == d){
24                 if(b2 == a3 && (b2 + a1 == d || b2 + b1 == d)) { cout << "YES" << endl; continue;}
25             }
26              if(g == d){
27                 if(a2 == b3 && (a2 + a1 == d || a2 + b1 == d)) { cout << "YES" << endl; continue;}
28             }
29              if(h == d){
30                 if(a2 == a3 && (a2 + a1 == d || a2 + b1 == d)) { cout << "YES" << endl; continue;}
31             }
32         }
33         else if(flag == 2){
34             int e = a1 + a3;
35             int f = a1 + b3;
36             int g = b1 + a3;
37             int h = b1 + b3;
38             if(e == d){
39                 if(b1 == b3 && (b1 + a2 == d || b1 + b2 == d)){ cout << "YES" << endl; continue;}
40             }
41             if(f == d){
42                 if(b1 == a3 && (b1 + a2 == d || b1 + b2 == d)) { cout << "YES" << endl; continue;}
43             }
44              if(g == d){
45                 if(a1 == b3 && (a1 + a2 == d || a1 + b2 == d)) { cout << "YES" << endl; continue;}
46             }
47              if(h == d){
48                 if(a1 == a3 && (a1 + a2 == d || a1 + b2 == d)) { cout << "YES" << endl; continue;}
49             }
50         }
51         else if(flag == 3){
52             int e = a2 + a1;
53             int f = a2 + b1;
54             int g = b2 + a1;
55             int h = b2 + b1;
56             if(e == d){
57                 if(b2 == b1 && (b1 + a3 == d || b1 + b3 == d)){ cout << "YES" << endl; continue;}
58             }
59             if(f == d){
60                 if(b2 == a1 && (b2 + a3 == d || b2 + b3 == d)) { cout << "YES" << endl; continue;}
61             }
62              if(g == d){
63                 if(a2 == b1 && (b1 + a3 == d || b1 + b3 == d)) { cout << "YES" << endl; continue;}
64             }
65              if(h == d){
66                 if(a2 == a1 && (a1 + a3 == d || a1 + b3 == d)) { cout << "YES" << endl; continue;}
67             }
68         }
69         cout << "NO" << endl;
70     }
71 }
View Code

 

M:题意是让你找最长交错子序列,这个序列是上升降低或者降低上升交错出现的。其实这个题的本质和A的最长上升子序列是同样的,

     最长上升是在每一个位置i咱们找的是i以前的最长上升,这道题换成了两种状况

     一种状况是假设当前要上升的话,咱们找i以前的最长降低。另外一种是假设当前降低,咱们找i以前的最长上升,用两个dp数组就能够解决了。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define rep(i,a,b) for(int i = a;i <= b;++ i)
 4 #define per(i,a,b) for(int i = a;i >= b;-- i)
 5 #define mem(a,b) memset((a),(b),sizeof((a)))
 6 #define FIN freopen("in.txt","r",stdin)
 7 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 8 #define pb push_back
 9 typedef long long LL;
10 typedef pair<int, LL> PIR;
11 const int N = 1e6+5;
12 
13 int n, a[55], dp[55][2];
14 
15 int main()
16 {
17     //FIN;
18     cin >> n;
19     rep(i, 1, n)    cin >> a[i];
20     int maxn = 1;
21     rep(i, 1, n){
22         dp[i][0] = dp[i][1] = 1;
23         rep(j, 1, i-1){
24             if(a[j] > a[i]) dp[i][0] = max(dp[i][0], dp[j][1]+1);
25             if(a[j] < a[i]) dp[i][1] = max(dp[i][1], dp[j][0]+1);
26         }
27         maxn = max(maxn, max(dp[i][0], dp[i][1]));
28     }
29     cout << maxn << endl;
30     return 0;
31 }
View Code
相关文章
相关标签/搜索