CF #578 Div2
// 比赛链接:https://codeforces.com/contest/1200
A - Hotelier
题意:
有一家旅馆有10间房,编号0~9,从左到右顺序排列。旅馆有左右两扇门,每次新来旅客从进来门的方向分配最近的空闲房间。给你一段旅客到来方向以及离开位置的序列,输出最终旅馆房间使用情况。
输入:
8
LLRL1RL1
输出:
1010000011
题解:
序列长度不超过10^5,暴力模拟复杂度O(10*n)。
AC代码:
#include<iostream> #include<cstdio> using namespace std; char s[100010]; bool r[10]; // true:有人 false:无人 int main() { int n; cin>>n; scanf("%s", s); for(int i=0;i<n;i++) { if(s[i]=='L') { for(int j=0;j<=9;j++) { if(!r[j]) { r[j] = 1; break; } } } else if(s[i]=='R') { for(int j=9;j>=0;j--) { if(!r[j]) { r[j] = 1; break; } } } else { r[s[i]-'0'] = 0; } } for(int i=0;i<=9;i++) { putchar(r[i]?'1':'0'); } return 0; }
B - Block Adventure
题意:
从起点到终点有 n 个格子,每块高度 h[i],初始时背包有m块方块,从 i 跳到 i+1 有三种选择,1. 把背包的方块放到当前的格子上;2. 把当前格子的方块放到背包里;3.跳到下一块。
只有当 | h[i] - h[i+1] | <= k 才能跳到下一块。 问是否能跳到终点。
输入:
第一行组数,后面每组第一行 n,m,k,第二行 n个值代表 h[i]。
5
3 0 1
4 3 5
3 1 2
1 4 7
4 10 0
10 20 10 20
2 5 5
0 11
1 9 9
99
输出:
YES
NO
YES
NO
YES
题解:
贪心。
如果能跳到下一块,(左边能凑到的最多方块要大于等于右边最少需要的方块,即m+h[i]>= h[i+1]-k ),把前一块上的方块取到前后差值不超过 k。否则跳不到终点。
AC代码:
#include<iostream> #include<cstdio> using namespace std; int h[110]; int main() { int t; cin>>t; while(t--) { int n, m, k; scanf("%d %d %d", &n, &m, &k); for(int i=0;i<n;i++) { scanf("%d", &h[i]); } bool flag = true; for(int i=0;i+1<n;i++) { if(h[i]+m>=h[i+1]-k) { if(h[i+1]>=k) m = h[i]+m - (h[i+1]-k); else m = h[i]+m; } else { flag = false; break; } } if(flag) printf("YES\n"); else printf("NO\n"); } return 0; }
C - Round Corridor
题意:
一个圆盘,内层分割成m块,外层分割成n块,给出 q 个询问,判断所给两块区域是否连通。
输入:
第一行 n,m,q,后面 q 行,每行四个数 sx,sy,ex,ey。sx,ex 为 1 代表内层,为 2 代表外层;sy,ey 代表编号,如图顺时针排序。
4 6 3
1 1 2 3
2 6 1 2
2 6 2 4
输出:
YES
NO
YES
题解:
思维题。设 g = gcd(m, n),由图可知 1*g,2*g,3*g,…… k*g 把圆盘分割开。这些单独块之内连通,不在同一块则不连通。
AC代码:
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; ll gcd(ll a, ll b) { return b==0?a:gcd(b, a%b); } ll g, m, n; ll f(int d, ll v) { // 计算 v 所在块的编号 if(d==1) return v/(m/g); else return v/(n/g); } int main() { int q; cin>>m>>n>>q; int sx, ex; ll sy, ey; g = gcd(m, n); while(q--) { scanf("%d %lld %d %lld", &sx, &sy, &ex, &ey); if(f(sx, sy-1)==f(ex, ey-1)) printf("YES\n"); else printf("NO\n"); } return 0; }
E - Compress
题意:
有1e5个单词,当前一个单词的后缀与后一个单词的前缀相同时,相同部分可以压缩省略,这个过程递归进行。输出一行字符串表示最终结果。
输入:
5
I want to order pizza
输出:
Iwantorderpizza
题解:
字符串哈希。
AC代码:
注意压缩过程是递归进行的,没注意一直WA5。
单模数哈希WA78,可能没取好模数吧。双模数哈希AC。
#include<cstdio> #include<cstring> #include<iostream> using namespace std; typedef long long ll; const int N = 1e6 + 10; const int Base1 = 1009; const int Base2 = 233; const int Mod1 = 1e9 + 7; const int Mod2 = 998244353; char s[N], ans[N]; int main() { int n; scanf("%d", &n); int len = 0; // 前一个串长度 for(int i = 0; i < n; ++i) { scanf("%s", s); int m = strlen(s); ll now1 = 0, last1 = 0; // 前面所有串的哈希,当前串的哈希 ll now2 = 0, last2 = 0; ll bs1 = 1, bs2 = 1; int same = 0; // 公共长度 for(int k = 1; k <= m && k <= len; ++k) { now1 = (now1*Base1 + s[k-1]) % Mod1; // 从前往后加 last1 = (bs1*ans[len-k] + last1) % Mod1; // 从后往前加 bs1 = bs1 * Base1 % Mod1; now2 = (now2*Base2 + s[k-1]) % Mod2; last2 = (bs2*ans[len-k] + last2) % Mod2; bs2 = bs2 * Base2 % Mod2; if(now1==last1 && now2==last2) same = k; } for(int k = same; k < m; ++k) { ans[len++] = s[k]; } } ans[len] = '\0'; puts(ans); return 0; }