Codeforces Round #578 (Div. 2) Solution
Problem A Hotelier
直接模拟即可~~
复杂度是$O(10 \times n)$
# include<bits/stdc++.h>
using namespace std;
const int N=1e5+;
char s[N];
bool a[];
int main()
{
int n; scanf("%d",&n); scanf("%s",s);
for (int i=;i<n;i++) {
if (s[i]=='L') {
for (int j=;j<=;j++)
if (!a[j]) { a[j]=true; break;}
} else if (s[i]=='R') {
for (int j=;j>=;j--)
if (!a[j]) { a[j]=true; break;}
} else a[s[i]-'']=;
}
for (int i=;i<=;i++) printf("%d",a[i]);
puts("");
return ;
}
A.cpp
Problem B Hotelier
注意到高度的限制是带绝对值的,化简为$H_{i+1} - k \leq H_i \leq H_{i+1}+k$
显然较高的限制是没有意义的,在一次最优的决策中不可能会选择当前从背包里面拿砖块去达到上界。
所以对于当前的决策来说,在保证仍然在高度下界以上,尽可能从地上拿砖块。
如果当前高度在高度下界以下,那么就需要从背包里拿出砖块使得到达高度下界。
注意到,地面的高度为$0$事实上,高度的下界是$\max\{H_{i+1} - k , 0\}$
复杂度是$O(T n)$
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=;
int n,m,k,h[N];
signed main()
{
int T; scanf("%lld",&T);
while (T--) {
scanf("%lld%lld%lld",&n,&m,&k);
for (int i=;i<=n;i++) scanf("%lld",&h[i]);
bool flag=true;
for (int i=;i<n;i++) {
int t=h[i]-max(h[i+]-k,0ll);
if (m+t>=) { m+=t; continue;}
else { flag=false; break;}
}
if (flag) puts("YES");else puts("NO");
}
return ;
}
B.cpp
Problem C Round Corridor
对于内部和外部的门,现在在一个连通块中是可以任意走动的,如果不在一个连通块中就不能。
对于图形可以划分成若干个连通块,当有重合的墙壁时会成为连通块的分界。第一个墙壁在12点钟方向已经重合。
非常明显接下来就是一个gcd类型的题目了。下面令$g = gcd(n,m)$
举例来说$[1,\frac{n}{g}] $和$[1,\frac{m}{g}]$ 是一个连通块.
形式化的说$[k \frac{n}{g}+1 , (k+1) \frac{n}{g}]$和$[k \frac{m}{g}+1 , (k+1) \frac{m}{g}] , k\in N $ 是一个连通块。
于是我们只需要判断如果在相同的连通块中就是"YES"否则就是"NO"
复杂度是$O(q)$
#include <bits/stdc++.h>
#define int long long
using namespace std; int n, m, q;
signed main()
{
cin >> n >> m >> q;
int lcmm = m / __gcd(n, m);
int lcmn = n / __gcd(n, m);
while (q --)
{
int sx, sy, ex, ey;
cin >> sx >> sy >> ex >> ey;
int p1 = , p2 = ;
if (sx == ) p1 = (sy + lcmn - ) / lcmn;
else p1 = (sy + lcmm - ) / lcmm;
if (ex == ) p2 = (ey + lcmn - ) / lcmn;
else p2 = (ey + lcmm - ) / lcmm;
if (p1 == p2) printf("YES\n");
else printf("NO\n");
}
}
C.cpp
Problem D White Lines
我们知道当前框的大小是不会发生变化的,对于一个左上角为$(i,j)$的正方形,覆盖到的范围是$(i,j) - (i+k-1,j+k-1)$
我们可以对行和列分别考虑,先考虑行,即求出在左上角为$(i,j)$的正方形点击,会造成多少行全是white。
对于每一行,我们记录最靠左黑点和最靠右白点的位置,只有覆盖这两个位置,该行才能被覆盖。
将已经全是白块的行忽略,这是因为无论怎么点击都是有贡献的。
首先可以暴力$O(k)$计算$(1,1)$的答案,于是问题转化为向下滑动这个$k\times k$的正方形来获取下一个答案。
在计算$(2,1) , (3,1)$等第一个安放的正方形的时候直接$O(k)$暴力计算,滑动一次判断进出的复杂度是$O(1)$的,
所以总复杂度是$O(n^2)$ 对于列的情况同理计算,答案就是同一位置两者之和的最大值。
# include<bits/stdc++.h>
using namespace std;
const int N=2e3+;
struct rec{
int l,r;
}c[N];
int a[N][N],n,k,ans[N][N];
char s[N];
int main()
{
scanf("%d%d",&n,&k);
for (int i=;i<=n;i++) {
scanf("%s",s+);
for (int j=;j<=n;j++)
if (s[j]=='B') a[i][j]=;
else a[i][j]=;
}
int ret=;
for (int i=;i<=n;i++) {
int l=n+,r=;
for (int j=;j<=n;j++)
if (a[i][j]==) l=min(l,j),r=max(r,j);
c[i].l=l; c[i].r=r;
if (c[i].r<c[i].l) ret++;
}
int rec=ret;
for (int j=;j<=n-k+;j++) {
for (int i=;i<=k;i++)
if (c[i].l<=c[i].r && j<=c[i].l&&c[i].r<=j+k-) ret++;
ans[][j]=ret;
for (int i=;i<=n-k+;i++) {
if (c[i-].l<=c[i-].r && j<=c[i-].l && c[i-].r<=j+k-) ret--;
if (c[i+k-].l<=c[i+k-].r && j<=c[i+k-].l && c[i+k-].r<=j+k-) ret++;
ans[i][j]=ret;
}
ret=rec;
}
ret=;
for (int j=;j<=n;j++) {
int l=n+,r=;
for (int i=;i<=n;i++)
if (a[i][j]==) l=min(l,i),r=max(r,i);
c[j].l=l; c[j].r=r;
if (c[j].r<c[j].l) ret++;
}
int res=; rec=ret;
for (int i=;i<=n-k+;i++) {
for (int j=;j<=k;j++)
if (c[j].l<=c[j].r && i<=c[j].l &&c[j].r<=i+k-) ret++;
res = max(res,ans[i][]+ret);
for (int j=;j<=n-k+;j++) {
if (c[j-].l<=c[j-].r && i<=c[j-].l && c[j-].r<=i+k-) ret--;
if (c[j+k-].l<=c[j+k-].r && i<=c[j+k-].l && c[j+k-].r <= i+k-) ret++;
res = max(res , ans[i][j]+ret);
}
ret=rec;
}
printf("%d\n",res);
return ;
}
D.cpp
Problem E Compress Words
可以使用双hash,然后题意不是两个相邻的单词合并,而是之前已经合并过的单词和下一个单词合并。
复杂度大概是$O(\sum |S_i|)$ ,其中$|S_i|$表示第$i$个单词的长度。
# include <cstdio>
# include <iostream>
# include <cstring>
# define hash Hash
# define e1 E1
# define e2 E2
# define mo1 MO1
# define mo2 MO2
# define int long long
using namespace std;
const int N=2e6+,e1=,e2=;
const int mo1=1e9+,mo2=;
int Pow1[N],Pow2[N];
string s1,s2;
int n;
struct StringHash{
pair<int,int> hash[N];
void build(string s) {
int len=s.length(); hash[]=make_pair(,);
for (int i=;i<=len;i++)
hash[i].first=(hash[i-].first*e1%mo1+s[i-])%mo1,
hash[i].second=(hash[i-].second*e2%mo2+s[i-])%mo2;
}
pair<int,int> gethash(int l,int r) {
pair<int,int>ans;
ans.first=((hash[r].first-Pow1[r-l+]*hash[l-].first%mo1)%mo1+mo1)%mo1;
ans.second=((hash[r].second-Pow2[r-l+]*hash[l-].second%mo2)%mo2+mo2)%mo2;
return ans;
}
}S,T;
void work()
{
int len1=s1.length(),len2=s2.length();
T.build(s2); int ans=;
for (int mid=;mid<=min(len1,len2);mid++)
if (S.gethash(len1-mid+,len1) == T.gethash(,mid)) ans=mid;
for (int i=ans;i<len2;i++) {
S.hash[i-ans++len1].first=(S.hash[i-ans+len1].first*e1%mo1+s2[i])%mo1,
S.hash[i-ans++len1].second=(S.hash[i-ans+len1].second*e2%mo2+s2[i])%mo2;
s1+=s2[i];
}
}
signed main() {
cin.sync_with_stdio(); cin.tie();
Pow1[]=Pow2[]=;
for (int i=;i<=;i++) Pow1[i]=Pow1[i-]*e1%mo1;
for (int i=;i<=;i++) Pow2[i]=Pow2[i-]*e2%mo2;
cin>>n; cin>>s1; S.build(s1);
for (int i=;i<=n;i++) {
cin>>s2; work();
}
cout<<s1;
return ;
}
E.cpp
Problem F White Lines
考虑到每个点的出度最大只有$10$。所以对于到达任意点的权$k$来说,只有$lcm(1..10) = 2520$种不同可能的后果。
所以所有权值$k$只需要在$mod 2520$的意义下计算就行。
记$ans[u][val]$表示当前到达顶点$u$当前带权为$val$的答案。
那么可以用记忆化搜索来维护这一条路径,然后用set来去重,就可以得到答案了。
由于每个点每个状态只可能访问一次,所以本题时间复杂度是$O(lcm(1..10) \times n)$
# include <bits/stdc++.h>
using namespace std;
const int N=,M=;
vector<int>E[N];
int k[N],ans[N][M],n;
bool vis[N][M];
pair<int,int>pre[N][M];
int dfs(int u,int val)
{
if (ans[u][val]) return ans[u][val];
vis[u][val]=;
int nex=(val+k[u])%;
int v=E[u][nex%E[u].size()];
if (ans[v][nex]) return ans[u][val]=ans[v][nex];
if (!vis[v][nex]) {
pre[v][nex]=make_pair(u,val);
return ans[u][val]=dfs(v,nex);
} else {
set<int>s;
pair<int,int> now = make_pair(u,val);
while (now!=make_pair(v,nex)) {
s.insert(now.first);
now=pre[now.first][now.second];
}
s.insert(now.first);
return ans[u][val]=s.size();
}
}
int main()
{
scanf("%d",&n);
for (int i=;i<=n;i++)
scanf("%d",&k[i]),k[i]=(k[i]%+)%;
for (int i=;i<=n;i++){
int t; scanf("%d",&t);
for (int j=;j<=t;j++) {
int v; scanf("%d",&v);
E[i].push_back(v);
}
}
int q; scanf("%d",&q);
while (q--) {
int x,y; scanf("%d%d",&x,&y);
printf("%d\n",dfs(x,(y%+)%));
}
return ;
}
F.cpp
Codeforces Round #578 (Div. 2) Solution的更多相关文章
- Codeforces Round #578 (Div. 2)
Codeforces Round #578 (Div. 2) 传送门 A. Hotelier 暴力即可. Code #include <bits/stdc++.h> using names ...
- Codeforces Round #466 (Div. 2) Solution
从这里开始 题目列表 小结 Problem A Points on the line Problem B Our Tanya is Crying Out Loud Problem C Phone Nu ...
- 老年OIer的Python实践记—— Codeforces Round #555 (Div. 3) solution
对没错下面的代码全部是python 3(除了E的那个multiset) 题目链接:https://codeforces.com/contest/1157 A. Reachable Numbers 按位 ...
- Codeforces Round #545 (Div. 1) Solution
人生第一场Div. 1 结果因为想D想太久不晓得Floyd判环法.C不会拆点.E想了个奇奇怪怪的set+堆+一堆乱七八糟的标记的贼难写的做法滚粗了qwq靠手速上分qwqqq A. Skyscraper ...
- Codeforces Round 500 (Div 2) Solution
从这里开始 题目地址 瞎扯 Problem A Piles With Stones Problem B And Problem C Photo of The Sky Problem D Chemica ...
- Codeforces Round #607 (Div. 1) Solution
从这里开始 比赛目录 我又不太会 div 1 A? 我菜爆了... Problem A Cut and Paste 暴力模拟一下. Code #include <bits/stdc++.h> ...
- Codeforces Round #525 (Div. 2) Solution
A. Ehab and another construction problem Water. #include <bits/stdc++.h> using namespace std; ...
- Codeforces Round #520 (Div. 2) Solution
A. A Prank Solved. 题意: 给出一串数字,每个数字的范围是$[1, 1000]$,并且这个序列是递增的,求最多擦除掉多少个数字,使得别人一看就知道缺的数字是什么. 思路: 显然,如果 ...
- Codeforces Round #523 (Div. 2) Solution
A. Coins Water. #include <bits/stdc++.h> using namespace std; int n, s; int main() { while (sc ...
随机推荐
- 【转帖】Linux上,最常用的一批命令解析(10年精选)
Linux上,最常用的一批命令解析(10年精选) https://juejin.im/post/5d134fbfe51d4510727c80d1 写的挺好呢 Linux这么多命令,通常会让初学者望而生 ...
- python之cookies
#cookies保存在文档头的内部,将cookies信息保存在文档中 userinfo={'} r=requests.get('http://httpbin.org/get',cookies=user ...
- 【面试向】hihoCoder 1994 树与落叶
题目链接 Implementation int n, q; scan(n,q); vi p(n + 1); vi nson(n + 1); up (i, 1, n) { scan(p[i]); nso ...
- CentOS7实现Nginx+Tomcat 负载均衡
0. 说明 将nginx作为负载均衡器,反向代理,tomcat作为节点服务器 192.168.100.201:nginx服务器 192.168.100.202:Tomcat 1服务器 192.168. ...
- 转载:JavaWeb 文件上传下载
转自:https://www.cnblogs.com/aaron911/p/7797877.html 1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端 ...
- mybatis原理解析
本文是结合spring-mybatis整合进行的分析 1.先看看依赖的jar包: <dependency> <groupId>org.mybatis</groupId&g ...
- 模块之time与datetime
模块之time与datetime import time print (time.clock()) print(time.process_time()) #测量处理器运算时间 print(time.a ...
- MP4 ISO基础媒体文件格式 摘要 1
目录 Object-structured File Organization 1 File Type Box (ftyp) Box Structures File Structure and gene ...
- Powershell - 获取服务器启动时间
www.orangeisland.cn 使用以下命令,直接获取服务器启动时间: 通过以下脚本,批量获取服务器的启动时间: $TextPath = "C:\Users\admin\Deskto ...
- 00常见的Linux系统版本
linux系统内核与linux发行套件系统并不相同: linux系统内核指的是一个由Linus Torvalds负责维护,提供硬件抽象层.硬盘及文件系统控制及多任务功能的系统核心程序. linux发行 ...