2020大一个人赛(10)题解 2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)
2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)部分题
A - Exam
题意:给你k(朋友正确个数)和两个字符串(你和你朋友的答案),问你能答对的最大个数
思路:找你和朋友相同的个数,然后进行判断就行。
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 2e6+25; 9 const int mod = 1e9 + 7; 10 ll a[N]; 11 int main() 12 { 13 ll n, ans = 0, sum = 0; 14 cin >> n; 15 string s1, s2; 16 cin >> s1 >> s2; 17 for (int i = 0; i < s1.size(); i++) 18 { 19 if (s1[i] == s2[i]) 20 ans++; 21 else 22 sum++; 23 } 24 if (ans == n) 25 cout << s1.size() << endl; 26 else if (ans > n) 27 cout << n + sum << endl; 28 else cout << s1.size() - (n - ans) << endl; 29 30 31 32 }
B - Coprime Integers
题意:给你区间【a,b】【c,d】,问你互质整数对的数量。
思路:莫比乌斯反演算法,反演公式如下:(群里有模板OvO)
献上代码
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 1e7+2; 9 const int mod = 1e9 + 7; 10 const int MAXN = 1e7+2; 11 bool check[MAXN + 10]; 12 int prime[MAXN + 10]; 13 int mu[MAXN + 10]; 14 void Moblus() 15 { 16 memset(check, false, sizeof(check)); 17 mu[1] = 1; 18 int tot = 0; 19 for (int i = 2; i <= MAXN; i++) 20 { 21 if (!check[i]) 22 { 23 prime[tot++] = i; 24 mu[i] = -1; 25 } 26 for (int j = 0; j < tot; j++) 27 { 28 if (i * prime[j] > MAXN) break; 29 check[i * prime[j]] = true; 30 if (i % prime[j] == 0) 31 { 32 mu[i * prime[j]] = 0; 33 break; 34 } 35 else 36 { 37 mu[i * prime[j]] = -mu[i]; 38 } 39 } 40 } 41 } 42 int sum[MAXN + 10]; 43 //找[1,n],[1,m]内互质的数的对数 44 long long solve(int n, int m) 45 { 46 long long 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 += (long long)(sum[la] - sum[i - 1]) * (n / i) * (m / i); 52 } 53 54 return ans; 55 } 56 int main() 57 { 58 Moblus(); 59 sum[0] = 0; 60 for (int i = 1; i <= MAXN; i++) 61 sum[i] = sum[i - 1] + mu[i]; 62 int a, b, c, d, k; 63 int T; 64 scanf("%d%d%d%d", &a, &b, &c, &d); 65 long long ans = solve(b, d) - solve((a - 1), d) - solve(b , (c - 1)) 66 + solve((a - 1), (c - 1)); 67 printf("%lld\n", ans); 68 69 return 0; 70 }
C - Contest Setting
题意:给你n个数和选取k种不同难度的题,问有多少方案。
思路:dp,dp[i][j]表示前i种选j个的方案数,先进行排序,算不同难度的个数存进数组,将其dp就是答案。
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 1e3+5; 9 const int mod = 998244353; 10 ll dp[N][N]; 11 ll kind[N]; 12 ll a[N]; 13 int main() 14 { 15 ll i, j, k; 16 ll n, t,count=0; 17 cin >> n >> k; 18 for (i = 1; i <= n; i++) 19 { 20 cin >> a[i]; 21 } 22 sort(a + 1, a + n + 1); 23 ll cnt = 1, tot = 1; 24 for (int i = 2; i <= n; i++)// 25 { 26 if (a[i] == a[i - 1]) 27 { 28 cnt++; 29 } 30 else 31 { 32 kind[tot++] = cnt; 33 cnt = 1; 34 } 35 } 36 kind[tot] = cnt;//算不同种的个数 37 memset(dp, 0, sizeof(dp)); 38 for (int i = 0; i <= 1000; i++) 39 { 40 dp[i][0] = 1; 41 } 42 for (i = 1; i <= tot; i++)//选第i种难度 43 { 44 for (j = 1; j <= k; j++)//选1-k个 45 { 46 dp[i][j] = ((dp[i - 1][j - 1] * kind[i] % mod) + dp[i - 1][j]) % mod; 47 } 48 } 49 cout << dp[tot][k] << endl; 50 51 52 53 54 }
D - Count The Bits
题意:给你整数k和b位数,问0-2^b-1被k整除的个数
思路:数位dp,
dp[i][j][0]表示前i位构成的数中对k取模为j的数的个数
dp[i][j][1]表示前i位构成的数中对k取模为j的数中二进制中1的个数
所求结果就是dp[b][0][1],即b位数能被k整除后二进制1的个数
代码
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 1e3+5; 9 const int mod = 1e9+9; 10 ll dp[129][N][2]; 11 //dp[i][j][0]表示前i位构成的数中对k取模为j的数的个数 12 //dp[i][j][1]表示前i位构成的数中对k取模为j的数中二进制中1的个数 13 14 int main() 15 { 16 ll i, j, k; 17 ll n,t,b; 18 cin >> k >> b; 19 dp[0][0][0] = 1; 20 dp[0][0][1] = 0; 21 for (i = 1; i <= b; i++)//前i位 22 { 23 for (j = 0; j < k; j++) 24 { 25 dp[i][j *2 % k][0] = (dp[i][(j *2) % k][0] + dp[i - 1][j][0]) % mod; 26 dp[i][(j*2 + 1) % k][0] = (dp[i][(j*2 + 1) % k][0] + dp[i - 1][j][0]) % mod; 27 28 dp[i][(j * 2) % k][1] = (dp[i][(j * 2) % k][1] + dp[i - 1][j][1]) % mod; 29 dp[i][(j * 2 + 1) % k][1] = (dp[i][(j * 2 + 1) % k][1] + dp[i - 1][j][1] + dp[i - 1][j][0]) %mod; 30 } 31 } 32 cout << dp[b][0][1]; 33 34 35 36 37 38 }
E - Goat on a Rope
题意:给你山羊(x,y),和矩形中心对称两端点(x1,y1)(x2,y2),求绳子I不到矩形的最大长度
思路,点到矩形的最近距离
代码
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 1e3+5; 9 const int mod = 1e9+9; 10 double cal(double x1, double y1, double x2, double y2) 11 { 12 return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); 13 } 14 int main() 15 { 16 ll i, j, k; 17 ll n, t, b; 18 double ans = mod; 19 double x, y, x1, x2, y2, y1; 20 cin >> x >> y >> x1 >> y1 >> x2 >> y2; 21 if (x >= min(x1, x2) && x <= max(x2, x1)) //在x1和x2之间,距离为与y的距离 22 ans = min(abs(y1 - y), abs(y2 - y)); 23 else if (y >= min(y1, y2) && y <= max(y1, y2))//在y1和y2之间,距离为与x的距离 24 ans = min(abs(x - x1), abs(x - x2)); 25 else 26 ans = min(cal(x, y, x1, y1), min(cal(x, y, x2, y2), min(cal(x, y, x1, y2), cal(x, y, x2, y1))));//四端点的距离 27 printf("%.3f\n", ans); 28 29 }
F - Repeating Goldbachs
题意:给你 一个数x(x≥4),将他拆分成两个质数,俩质数之差得到一个数再拆分,直至x<4,问多少步
思路:打表质数,然后暴力即可
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 1e6+5; 9 const int mod = 1e9+9; 10 bool vis[N + 100]; 11 ll prime[N + 100]; 12 ll cnt = 0; 13 void dabiao() 14 { 15 vis[0] = vis[1] = 1; 16 for (int i = 2; i <= N; i++) 17 { 18 if (!vis[i]) 19 { 20 prime[cnt++] = i; 21 for (int j = i + i; j <= N; j += i) 22 vis[j] = 1; 23 } 24 } 25 } 26 int main() 27 { 28 ll i, j, k; 29 ll n, t, b; 30 dabiao(); 31 cin >> n; 32 ll tmp = n,count=0; 33 while (tmp >= 4) 34 { 35 for (j = 0; j < cnt; j++) 36 { 37 k = tmp - prime[j]; 38 if (vis[k] == 0) 39 { 40 count++; 41 tmp = abs(k - prime[j]); 42 break; 43 } 44 } 45 } 46 cout << count << endl; 47 }
G - The Ending Point
题意:给你起点(x,y)和一个字符串(上下左右),问终点
思路:纯代入
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 2e6+25; 9 const int mod = 1e9 + 7; 10 ll a[N]; 11 int main() 12 { 13 ll i, j, k; 14 ll n, m, t; 15 ll x, y; 16 string s; 17 cin >> x >> y; 18 cin >> s; 19 for (i = 0; i < s.size(); i++) 20 { 21 if (s[i] == 'U') 22 y++; 23 else if (s[i] == 'D') 24 y--; 25 else if (s[i] == 'L') 26 x--; 27 else if (s[i] == 'R') 28 x++; 29 } 30 cout << x << " " << y; 31 32 33 34 }
H - Weird Game
题意:给你n个蛋糕,有两个操作可以选择:吃一个,吃半个,Mahmoud先吃,Bashar后吃,蛋糕剩一个的时候对手输,两个人玩的很好。
思路:简单思路型的博弈论,当n为奇数时,达到权衡,Bashar跟着Mahmoud吃一样的量,达到胜利,相反n为偶数时,Mahmoud胜利。
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 2e6+25; 9 const int mod = 1e9 + 7; 10 ll a[N]; 11 int main() 12 { 13 ll i, j, k; 14 ll n, m, t; 15 ll x, y; 16 cin >> n; 17 if(n%2==0) 18 puts("Mahmoud"); 19 else 20 puts("Bashar"); 21 22 23 24 }
I - Time Limits
题意:给你n个t毫秒时间和s倍,求以整数秒限制所有的t。
思路:找最大的t,乘s倍,毫秒变整数秒向上取整(我直接+999省工作23333)
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 2e6+25; 9 const int mod = 1e9 + 7; 10 ll a[N]; 11 int main() 12 { 13 ll i, j, k; 14 ll n, m, t; 15 ll x, y,s; 16 cin >> n>>s; 17 for (i = 0; i < n; i++) 18 cin >> a[i]; 19 sort(a, a + n); 20 cout << (a[n - 1] * s + 999) / 1000 << endl; 21 22 23 24 }