2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) Solution

A:Exam

Solved.

温暖的签。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxn = 1e3 + 10;
 6 
 7 int k;
 8 char str1[maxn], str2[maxn];
 9 
10 int main()
11 {
12     while(~scanf("%d",&k))
13     {
14         scanf("%s", str1 + 1);
15         scanf("%s", str2 + 1);
16         int cnt1 = 0, cnt2 = 0;
17         int len = strlen(str1 + 1);
18         for(int i = 1; i <= len; ++i)
19         {
20             if(str1[i] == str2[i]) cnt1++;
21             else cnt2++;
22         }
23         int ans = 0;
24         if(cnt1 >= k)
25         {
26             ans = k + cnt2;
27         }
28         else 
29         {
30             ans = len - (k - cnt1);
31         }
32         printf("%d\n", ans);
33     }
34     return 0;
35 }
View Code

 

B:Coprime Integers

Solved.

枚举gcd反演

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const int maxn = 1e7 + 10;
 8 
 9 bool check[maxn];
10 int prime[maxn];
11 ll mu[maxn];
12 
13 void Moblus()
14 {
15     memset(check, false, sizeof check);
16     mu[1] = 1;
17     int tot = 0;
18     for(int i = 2; i < maxn; ++i)
19     {
20         if(!check[i])
21         {
22             prime[tot++] = i;
23             mu[i] = -1;
24         }
25         for(int j = 0; j < tot; ++j)
26         {
27             if(i * prime[j] > maxn) break;
28             check[i * prime[j]] = true;
29             if(i % prime[j] == 0)
30             {
31                 mu[i * prime[j]] = 0;
32                 break;
33             }
34             else 
35             {
36                 mu[i * prime[j]] = -mu[i];
37             }
38         }
39     }
40 }
41 
42 ll sum[maxn];
43 
44 ll calc(int n, int m)
45 {
46     ll ans = 0;
47     if(n > m) swap(n, m);
48     for(int i = 1, la = 0; i <= n; i = la + 1)
49     {
50         la = min(n / (n / i), m / (m / i));
51         ans += (ll)(sum[la] - sum[i - 1]) * (n / i) * (m / i);
52     }
53     return ans;
54 }    
55 
56 ll a, b, c, d;
57 
58 int main()
59 {
60     Moblus();
61     for(int i = 1; i < maxn; ++i) sum[i] = sum[i - 1] + mu[i];
62     while(~scanf("%lld %lld %lld %lld", &a, &b, &c, &d))
63     {
64         ll ans = calc(b, d) - calc(a - 1, d) - calc(b, c - 1) + calc(a - 1, c - 1);
65         printf("%lld\n", ans);
66     }
67     return 0;
68 }
View Code

 

C:Contest Setting

Solved.

题意:

有n个题目,每个题目的难度值不同,要选出k个组成一套$Contest$

要求每个题目难度不同,求方案数

思路:

$把难度值相同的题目放在一起作为一种 dp[i][j] 表示选到第i种题目,已经选了k种的方案数$

$然后做01背包即可,注意加上的值为cnt[i] 表示该种题目有多少个$

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const ll MOD = 998244353;
 8 const int maxn = 1e3 + 10;
 9 
10 int n, k, pos;
11 ll cnt[maxn];
12 ll dp[maxn];
13 map<int, int>mp;
14 
15 int main()
16 {
17     while(~scanf("%d %d", &n, &k))
18     {
19         mp.clear();
20         pos = 0;
21         memset(cnt, 0, sizeof cnt);
22         for(int i = 1; i <= n; ++i)
23         {
24             int num;
25             scanf("%d", &num);
26             if(mp[num] == 0) mp[num] = ++pos;
27             int id = mp[num];
28             cnt[id]++;
29         }
30         memset(dp, 0, sizeof dp);
31         dp[0] = 1;
32         for(int i = 1; i <= pos; ++i)
33         {
34             for(int j = k; j >= 1; --j)
35             {
36                 dp[j] = (dp[j] + dp[j - 1] * cnt[i] % MOD) % MOD;
37             }
38         }
39         printf("%lld\n", dp[k]);
40     }
41     return 0;
42 }
View Code

 

D:Count The Bits

Solved.

题意:

在$[0, 2^b - 1] 中所有k的倍数以二进制形式表示有多少个1$

思路:

$dp[i][j] 表示枚举二进制位数,j 模k的余数, 表示的是前i位中模k的余数为j的数中1的个数$

$cnt[i][j] 表示当前二进制位为第i位, 模k的余数为j的数的个数$

直接转移即可。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const ll MOD = (ll)1e9 + 9;
 8 const int maxn = 1e3 + 10;
 9 
10 int k, b;
11 ll cnt[maxn][maxn];
12 ll dp[maxn][maxn];
13 
14 int main()
15 {
16     while(~scanf("%d %d", &k, &b))
17     {
18         memset(cnt, 0, sizeof cnt);
19         memset(dp, 0, sizeof dp);
20         cnt[1][0]++;
21            cnt[1][1 % k]++;
22         dp[1][1 % k]++;
23         ll tmp = 1;
24         for(int i = 1; i <= b; ++i)
25         {
26             tmp = (tmp << 1) % k;
27             for(int j = 0; j < k; ++j)
28             {
29                 //0
30                 cnt[i + 1][j] = (cnt[i + 1][j] + cnt[i][j]) % MOD;
31                 dp[i + 1][j] = (dp[i + 1][j] + dp[i][j]) % MOD;
32                 //1
33                 ll tmp2 = (tmp + j) % k;
34                 cnt[i + 1][tmp2] = (cnt[i + 1][tmp2] + cnt[i][j]) % MOD;
35                 dp[i + 1][tmp2] = ((dp[i + 1][tmp2] + cnt[i][j]) % MOD + dp[i][j]) % MOD;
36             }
37         }
38         printf("%lld\n", dp[b][0]);
39     }
40     return 0;
41 }
View Code
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 1010
 5 #define ll long long
 6 const ll MOD = (ll)1e9 + 9;
 7 ll dp[N][N], cnt[N][N];
 8 int n, k;
 9 
10 int main()
11 {
12     while (scanf("%d%d", &k, &n) != EOF)
13     {
14         memset(dp, 0, sizeof dp);
15         memset(cnt, 0, sizeof cnt);
16         ++dp[1][1 % k];
17         ++cnt[1][1 % k];
18         ++cnt[1][0];     
19         ll tmp = 1 % k;  
20         for (int i = 2; i <= n; ++i)
21         {
22             tmp = tmp * 2 % k; 
23             for (int j = 0; j < k; ++j) 
24             {
25                 dp[i][j] = dp[i - 1][j];   
26                 cnt[i][j] = cnt[i - 1][j]; 
27                 if (j - tmp >= 0) 
28                 {
29                     dp[i][j] = (dp[i][j] + dp[i - 1][j - tmp] + cnt[i - 1][j - tmp]) % MOD;
30                     cnt[i][j] = (cnt[i][j] + cnt[i - 1][j - tmp]) % MOD; 
31                 }
32                 else 
33                 {
34                     dp[i][j] = (dp[i][j] + dp[i - 1][k + j - tmp] + cnt[i - 1][k + j - tmp]) % MOD;
35                     cnt[i][j] = (cnt[i][j] + cnt[i - 1][k + j - tmp]) % MOD; 
36                 }
37             }    
38         }
39         printf("%lld\n", dp[n][0]);
40     }
41     return 0;
42 }
View Code

 

 

E:Cops And Robbers

Solved.

题意:

在一个$n * m 的矩阵中,有些地方可以建墙,但是不同的墙开销不同,求最小开销把劫匪围住$

思路:

拆点最小割,但是是点权,拆点即可。

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std; 
  4 
  5 const int maxn = 4e3 + 10;
  6 const int INF = 0x3f3f3f3f;
  7 
  8 struct Edge{
  9     int to, flow, nxt;
 10     Edge(){}
 11     Edge(int to, int nxt, int flow):to(to), nxt(nxt), flow(flow){}
 12 }edge[maxn << 2];
 13 
 14 int head[maxn], dep[maxn];
 15 int S,T;
 16 int N, n, m, tot;
 17 
 18 void Init(int n)
 19 {
 20     N = n;
 21     //memset(head, -1, sizeof head);
 22     for(int i = 0; i < N; ++i) head[i] = -1;
 23     tot = 0;
 24 }
 25 
 26 void addedge(int u, int v, int w, int rw = 0)
 27 {
 28     edge[tot] = Edge(v, head[u], w); head[u] = tot++;
 29     edge[tot] = Edge(u, head[v], rw); head[v] = tot++;
 30 }
 31 
 32 bool BFS()
 33 {
 34     //memset(dep, -1, sizeof dep);
 35     for(int i = 0; i < N; ++i) dep[i] = -1;
 36     queue<int>q;
 37     q.push(S);
 38     dep[S] = 1;
 39     while(!q.empty())
 40     {
 41         int u = q.front();
 42         q.pop();
 43         for(int i = head[u]; ~i; i = edge[i].nxt)
 44         {
 45             if(edge[i].flow && dep[edge[i].to] == -1)
 46             {
 47                 dep[edge[i].to] = dep[u] + 1;
 48                 q.push(edge[i].to);
 49             }
 50         }
 51     }
 52     return dep[T] < 0 ? 0 : 1;
 53 }
 54 
 55 int DFS(int u, int f)
 56 {
 57     if(u == T || f == 0) return f;
 58     int w, used = 0;
 59     for(int i = head[u]; ~i; i = edge[i].nxt)
 60     {
 61         if(edge[i].flow && dep[edge[i].to] == dep[u] + 1)
 62         {
 63             w = DFS(edge[i].to, min(f - used, edge[i].flow));
 64             edge[i].flow -= w;
 65             edge[i ^ 1].flow += w;
 66             used += w;
 67             if(used == f) return f;
 68         }
 69     }
 70     if(!used) dep[u] = -1;
 71     return used;
 72 }
 73 
 74 int Dicnic()
 75 {
 76     int ans = 0;
 77     while(BFS())
 78     {
 79         int tmp = DFS(S, INF); 
 80         if(tmp == INF) return -1;
 81         ans += tmp;
 82     }
 83     return ans;
 84 }
 85 
 86 int c;
 87 int C[maxn];
 88 char mp[100][100];
 89 
 90 int calc(int i, int j)
 91 {
 92     return i * 31 + j;
 93 }
 94 
 95 int main()
 96 {
 97     while(~scanf("%d %d %d", &m, &n, &c))
 98     {
 99         int base = n * 31 + m + 31;
100         int x, y;
101         Init(4000);
102         for(int i = 1; i <= n; ++i)
103         {
104             for(int j = 1; j <= m; ++j)
105             {
106                 scanf(" %c", &mp[i][j]);
107                 if(mp[i][j] == 'B') { x = i, y = j; }
108             }
109         }
110         for(int i = 1; i <= c; ++i) scanf("%d", C + i);
111         S = 0, T = calc(x, y);
112         for(int i = 1; i <= n; ++i)
113         {
114             addedge(S, calc(i, 1), INF);
115             addedge(S, calc(i, m), INF);    
116         }
117         for(int i = 1; i <= m; ++i)
118         {
119             addedge(S, calc(1, i), INF);
120             addedge(S, calc(n, i), INF);
121         }
122         for(int i = 1; i <= n; ++i)
123         {
124             for(int j = 1; j <= m; ++j)
125             {
126                 if(i != n)
127                 {
128                     addedge(calc(i, j) + base, calc(i + 1, j), INF);
129                     addedge(calc(i + 1, j) + base, calc(i, j), INF);
130                 }
131                 if(j != m)
132                 {
133                     addedge(calc(i, j)+ base, calc(i, j + 1), INF);
134                     addedge(calc(i, j + 1) + base, calc(i, j), INF);
135                 }
136             }
137         }
138         for(int i = 1; i <= n; ++i)
139         {
140             for(int j = 1; j <= m; ++j)
141             {
142                 if(mp[i][j] >= 'a' && mp[i][j] <= 'z')
143                 {
144                     addedge(calc(i, j), calc(i, j) + base, C[mp[i][j] - 'a' + 1]);
145                 }
146                 else 
147                 {
148                     addedge(calc(i, j), calc(i, j) + base, INF);
149                 }
150             }
151         }
152         int ans = Dicnic();
153         printf("%d\n", ans);
154     }
155     return 0;
156 }
View Code

 

F:Rectangles

Solved.

题意:

二维平面上有一些平行坐标轴的矩形,求有多少区间是被奇数个矩形覆盖。

思路:

扫描线,只是把区间加减换成区间01状态翻转,现场学扫描线可还行..

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define ll long long
  5 #define N 200010
  6 #define pii pair <int, int>
  7 int n, mx, my, bx[N], by[N];
  8 ll res;
  9 struct Rec
 10 {
 11     int x[2], y[2]; 
 12     void scan()
 13     {
 14         for (int i = 0; i < 2; ++i) scanf("%d%d", x + i, y + i);
 15         if (x[0] > x[1]) swap(x[0], x[1]);
 16         if (y[0] > y[1]) swap(y[0], y[1]);
 17         bx[++mx] = x[0];
 18         bx[++mx] = x[1];
 19         by[++my] = y[0];
 20         by[++my] = y[1]; 
 21     }
 22 }rec[N];
 23 vector <pii> v[N];  
 24 
 25 void Hash()
 26 {
 27     sort(bx + 1, bx + 1 + mx);
 28     sort(by + 1, by + 1 + my);
 29     mx = unique(bx + 1, bx + 1 + mx) - bx - 1;
 30     my = unique(by + 1, by + 1 + my) - by - 1;
 31     for (int i = 1; i <= n; ++i) 
 32     {
 33         for (int j = 0; j < 2; ++j)
 34         {
 35             rec[i].x[j] = lower_bound(bx + 1, bx + 1 + mx, rec[i].x[j]) - bx;
 36             rec[i].y[j] = lower_bound(by + 1, by + 1 + my, rec[i].y[j]) - by; 
 37         }
 38     }
 39 }
 40 
 41 namespace SEG
 42 {
 43     struct node
 44     {
 45         ll sum, val;
 46         int lazy; 
 47         node () {}
 48         node (ll sum, ll val, int lazy) : sum(sum), val(val), lazy(lazy) {}
 49         void init() { sum = val = lazy = 0; }
 50         node operator + (const node &other) const { return node(sum + other.sum, val + other.val, 0); }
 51         void Xor() { val = sum - val; lazy ^= 1; }   
 52     }a[N << 2];
 53     void build(int id, int l, int r)
 54     {
 55         a[id] = node(0, 0, 0);
 56         if (l == r) 
 57         {
 58             a[id].sum = by[l + 1] - by[l];
 59             return;
 60         }
 61         int mid = (l + r) >> 1;
 62         build(id << 1, l, mid);
 63         build(id << 1 | 1, mid + 1, r);
 64         a[id] = a[id << 1] + a[id << 1 | 1];
 65     }
 66     void pushdown(int id)
 67     {
 68         if (!a[id].lazy) return;
 69         a[id << 1].Xor();
 70         a[id << 1 | 1].Xor();
 71         a[id].lazy = 0;
 72     }
 73     void update(int id, int l, int r, int ql, int qr)
 74     {
 75         if (l >= ql && r <= qr) 
 76         {
 77             a[id].Xor();
 78             return;
 79         }
 80         int mid = (l + r) >> 1;
 81         pushdown(id);
 82         if (ql <= mid) update(id << 1, l, mid, ql, qr);
 83         if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr);
 84         a[id] = a[id << 1] + a[id << 1 | 1];
 85     }
 86 }
 87 
 88 int main()
 89 {
 90     while (scanf("%d", &n) != EOF)
 91     {
 92         mx = my = 0; res = 0; 
 93         for (int i = 1; i <= 2 * n; ++i) v[i].clear();
 94         for (int i = 1; i <= n; ++i) rec[i].scan(); Hash();    
 95         for (int i = 1; i <= n; ++i) 
 96         {
 97             v[rec[i].x[0]].emplace_back(rec[i].y[0], rec[i].y[1] - 1);
 98             v[rec[i].x[1]].emplace_back(rec[i].y[0], rec[i].y[1] - 1); 
 99         }
100         n <<= 1;    
101         SEG::build(1, 1, n);  
102         for (int i = 1; i < mx; ++i)
103         {
104             for (auto it : v[i]) SEG::update(1, 1, n, it.first, it.second);
105             res += (bx[i + 1] - bx[i]) * SEG::a[1].val;    
106         }
107         printf("%lld\n", res); 
108     }
109     return 0;
110 }
View Code

 

G:Goat on a Rope

Solved.

签到。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 double x, y;
 6 double xa, xb, ya, yb;
 7 
 8 double calc(double xa, double ya, double xb, double yb)
 9 {
10     return sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb));
11 }
12 
13 int main()
14 {
15     while(~scanf("%lf %lf %lf %lf %lf %lf", &x, &y, &xa, &ya, &xb, &yb))
16     {
17         double ans = 1e9;
18         if(x >= min(xa, xb) && x <= max(xa, xb)) ans = min(ans, min(fabs(y - ya), fabs(y - yb)));
19         if(y >= min(ya, yb) && y <= max(ya, yb)) ans = min(ans, min(fabs(x - xa), fabs(x - xb)));
20         ans = min(ans, calc(x, y, xa, ya));
21         ans = min(ans, calc(x, y, xa, yb));
22         ans = min(ans, calc(x, y, xb, ya));
23         ans = min(ans, calc(x, y, xb, yb));
24         printf("%.3f\n", ans);
25     }
26     return 0;
27 }
View Code

 

H:Repeating Goldbachs

Solved.

签到。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxn = 1e6 + 10;
 6 
 7 bool isprime[maxn];
 8 int prime[maxn];
 9 
10 void Init()
11 {
12     memset(isprime, true, sizeof isprime);
13     isprime[0] = isprime[1] = false;
14     for(int i = 2; i < maxn; ++i)
15     {
16         if(isprime[i])
17         {
18             prime[++prime[0]] = i;
19             for(int j = i * 2; j < maxn; j += i)
20             {
21                 isprime[j] = false;
22             }
23         }
24     }
25 }
26 
27 int x;
28 
29 int main()
30 {
31     Init();
32     while(~scanf("%d", &x))
33     {
34         int ans = 0;
35         while(x >= 4)
36         {
37             for(int i = 1; i <= prime[0]; ++i)
38             {
39                 int tmp = prime[i];
40                 if(isprime[x - tmp])
41                 {
42                     ++ans;
43                     x = x - tmp - tmp;
44                     break;
45                 }
46             }
47         }
48         printf("%d\n", ans);
49     }
50     return 0;
51 }
View Code

 

I:Inversions

Unsolved.

题意:

给出一些序列,一些位置上的数字可以在$[1, k]的范围内随便填,求如果填使得整个序列的逆序对个数最多$

 

J:Time Limits

Solved.

签到。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int n, s;
 6 
 7 int main()
 8 {
 9     while(~scanf("%d %d", &n, &s))
10     {
11         int Max = -1;
12         for(int i = 1; i <= n; ++i)
13         {
14             int num;
15             scanf("%d", &num);
16             Max = max(Max, num);
17         }
18         Max *= s;
19         int ans = Max / 1000;
20         if(Max % 1000) ans++;
21         printf("%d\n", ans);
22     }
23     return 0;
24 }
View Code

 

K:Knockout

Unsolved.

题意:

给出一个数字,然后两个骰子的点数,每次可以移掉数字当中某几位加起来的和等于两骰子点数之和

那么就可以移掉这几位,知道最后不能移位置,最后剩下的数就是分数

现在给出一中间局面,求移掉哪些,使得最后的分数期望最大以及最小

 

L:Liars

Solved.

签到。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxn = 1e3 + 10;
 6 
 7 int n;
 8 int cnt[maxn];
 9 
10 int main()
11 {
12     while(~scanf("%d", &n))
13     {
14         memset(cnt, 0, sizeof cnt);
15         for(int i = 1; i <= n; ++i)
16         {
17             int ai, bi;
18             scanf("%d %d", &ai, &bi);
19             for(int j = ai; j <= bi; ++j)
20             {
21                 cnt[j]++;
22             }
23         }
24         int ans = -1;
25         for(int i = 1; i <= n; ++i)
26         {
27             if(cnt[i] == i) ans = i;
28         }
29         printf("%d\n", ans);
30     }
31     return 0;
32 }
View Code

 

M:Mobilization

Unsolved.

题意:

$有m种军队,每种军队有h_i 属性 和 p_i属性,以及购买一支军队需要c_i的钱,每种军队可以购买无限支$

$现在你有C个单位的钱,求如何购买军队,使得\sum h_i \cdot \sum p_i 最大$

 

posted @ 2018-12-08 08:26  Dup4  阅读(1010)  评论(0编辑  收藏  举报