Codeforces Round #578 (Div. 2)
Codeforces Round #578 (Div. 2) 简易题解
A. Hotelier
题意
就是模拟客人进酒店
有n个客人有动作
L表示找到左边第一个空的住进去
R表示找到右边第一个空的住进去
数字表示第几间房子的人走了
题解
模拟即可
#include<bits/stdc++.h>
using namespace std;
int n, ans[15];
int main(){
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i ++){
char ch;
cin >> ch;
if(ch == 'L'){
for(int j = 0; j < 10; j ++){
if(!ans[j]){
ans[j] = 1;
break;
}
}
}else
if(ch == 'R'){
for(int j = 9; j >= 0; j --){
if(!ans[j]){
ans[j] = 1;
break;
}
}
}else{
ans[ch - '0'] = 0;
}
}
for(int i = 0; i < 10; i ++) cout << ans[i];
return 0;
}
B. Block Adventure
题意
一个人在跳柱子,每个柱子有一定的高度,那个人有个背包,可是塞无限多的东西,一开始有一定数量的垫脚石,每次可以把石柱砍掉一节塞进包里或从包里拿出来垫脚,要跳到下一个柱子仅当高度差不超过k,问是否可以跳到终点
贪心即可
#include<bits/stdc++.h>
using namespace std;
int n, a[1005], t, m, k;
int main(){
ios::sync_with_stdio(false);
cin >> t;
while(t--){
int F = 0;
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i < n; i ++){
int tt = max(a[i + 1] - k, 0);
m += a[i] - tt;
if(m < 0){
F = 1;
break;
}
}
if(F) cout << "NO" << endl;
else cout << "YES" << endl;
}
return 0;
}
C. Round Corridor
题意
比较清晰,就是有两圈,里面一圈平均分为n段,外面一圈平均分为m段,问两端直接是否相同
题解
他们的分界个数就是gcd,然后分一下块就可以了
#include<bits/stdc++.h>
#define int long long
using namespace std;
long long gcd(long long a, long long b){
return b? gcd(b, a % b):a;
}
long long n, m, q, a, b, c, d;
signed main(){
ios::sync_with_stdio(false);
cin >> n >> m >> q;
long long d = gcd(n, m);
int nn = n / d, mm = m / d;
while(q --){
cin >> a >> b >> c >> d;
if(a == 1) b = (b - 1) / nn + 1;
else b = (b - 1) / mm + 1;
if(c == 1) d = (d - 1) / nn + 1;
else d = (d - 1) / mm + 1;
if(b == d) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
D. White Lines
大意
给出一个 n ∗ n n*n n∗n的黑白矩阵,可以将一个 k ∗ k k*k k∗k的矩阵变为白色,问最多可以产生多少条白线(行或列只有白色)
题解
行列分开做,最后加在一起即可
#include<bits/stdc++.h>
using namespace std;
int n, m, k, a[5005][2005], h[2005][2005], l[2005][2005], ans1[2005][2005], ans2[2005][2005];
int main(){
ios::sync_with_stdio(false);
cin >> n >> k;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++){
char ch;
cin >> ch;
if(ch == 'B') a[i][j] = 1;
}
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
h[i][j] = h[i][j - 1] + a[i][j];//做第i行的前缀和
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
l[i][j] = l[i][j - 1] + a[j][i];//做第i列的前缀和
int ans = 0;
for(int i = 1; i <= n; i ++){//先把能加的加了
if(h[i][n] == 0) ans ++;
if(l[i][n] == 0) ans ++;
}
int tt = 0;
for(int i = 1; i <= n; i ++){//先做列,可以理解为把一个矩阵不断向右移,可以增加的白线列数
tt = 0;
for(int j = 1; j <= n; j ++){
if(l[j][i] - l[j][max(i - k, 0)] == l[j][n] && l[j][n]) tt ++;
if(j > k && l[j - k][i] - l[j - k][max(i - k, 0)] == l[j - k][n] && l[j - k][n]) tt --;
ans1[i][j] = tt;
}
}
for(int i = 1; i <= n; i ++){//同上
tt = 0;
for(int j = 1; j <= n; j ++){
if(h[j][i] - h[j][max(i - k, 0)] == h[j][n] && h[j][n]) tt ++;
if(j > k && h[j - k][i] - h[j - k][max(i - k, 0)] == h[j - k][n] && h[j - k][n]) tt --;
ans2[i][j] = tt;
}
}
int anss = 0;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
anss = max(anss, ans1[i][j] + ans2[j][i]);//更新答案
cout << ans + anss;
return 0;
}
E. Compress Words
题意
题意比较清楚了,看样例都猜得出来
题解
大力hash(自然溢出会被卡)
#include<bits/stdc++.h>//codef****
#define int long long
#define N 8000005
#define mod 19260817//这个模数可以过(很暴力
using namespace std;
int n;
long long pw[N], ha[N], haa[N];
string st;
int cg(char x){
return x;
}
signed main () {
ios::sync_with_stdio(false);
cin >> n;
int L = 0;
pw[0] = 1;
for(int i = 1; i <= 4000000; i++) pw[i] = pw[i - 1] * 16631 % mod;
for(int i = 1; i <= n; i++) {
cin >> st;
int len = st.length();
for(int j = 1; j <= len; j++) ha[j] = (ha[j - 1] * 16631 % mod + cg(st[j - 1]))% mod;
int l;
for(l = min(L, len); l; l--) {
int x = ha[l];
int y = (haa[L] - haa[L - l] * pw[l] % mod + mod) % mod;
if(x == y) break;
}
for(int j = l; j < len; j++) cout << st[j], haa[L + j - l + 1] = (haa[L + j - l] * 16631 % mod + cg(st[j])) % mod;
L += (len - l);
}
}
F. Graph Traveler
题意
比较复杂,自行理解吧
Gildong正在试验一个有趣的Graph Traveler,具体来说,这个Graph Traveler是个由n个编号为1-n的点构成的有向图,第i个点有
m
i
m_i
mi条出边,边到达的点分别被记为
e
i
[
0
]
,
e
i
[
1
]
.
.
.
e
i
[
m
i
−
1
]
e_i[0],e_i[1]...e_i[m_i-1]
ei[0],ei[1]...ei[mi−1].每个点还有点权
k
i
k_i
ki
现在有 q q q个询问,每个询问要求从某个点开始,初始有个点权 c c c,每次到一个点 i i i(起点也算)就把点权 c c c加上 k i k_i ki ,然后走 i i i的出边 e i [ x ] ( x ≡ c m o d    m i ) e_i[x](x \equiv c\mod m_i) ei[x](x≡cmodmi).可以发现这个过程是会一直进行下去的.现在问每次这样走,图上有多少个点会被经过无限次
题解
发现有用的状态只有
l
c
m
(
1
,
2
,
3
,
4
,
5
,
.
.
.
.
,
10
)
∗
n
lcm(1,2,3,4,5,....,10) * n
lcm(1,2,3,4,5,....,10)∗n个,然后暴力找环即可
我的写法比较巧妙,自行理解吧
#include<bits/stdc++.h>
#define mod 2520
#define N 1005
using namespace std;
int dep, f[N][mod], ck[N], n, k[N], q;
vector<int> a[N];
int dfs(int x, int y) {
if(f[x][y] > 0) return f[x][y];
if(f[x][y] < 0) {
int sz = 0;
for(int i = 1; i <= n; i ++) sz += (ck[i] <= f[x][y]);
return f[x][y] = sz;
}
f[x][y] = ck[x] = -- dep;
int yy = (y + k[x]) % a[x].size();
return f[x][y] = dfs(a[x][yy], (y + k[x]) % mod);
}
int main() {
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i ++) cin >> k[i], k[i] = (k[i] % mod + mod) % mod;
for(int i = 1; i <= n; i ++) {
int x, y;
cin >> x;
while(x --) cin >> y, a[i].push_back(y);
}
cin >> q;
while(q --) {
int x, y;
cin >> x >> y;
y = (y % mod + mod) % mod;
cout << dfs(x, y) << endl;
}
return 0;
}