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 ...
随机推荐
- 【新功能前瞻】SpreadJS 纯前端表格控件V12.2:打印增强、拖拽填充等六大特性
新版本来袭:葡萄城 SpreadJS 纯前端表格控件的全新版本 V12.2 将于8月正式发布! 作为一款备受华为.招商银行.中国平安.苏宁易购等行业专家和前端开发者认可的纯 JavaScript 电子 ...
- Java基础(六)
面向对象 概述 生活举例 代码体验 类与对象的关系 类的定义 根据类创建对象 对象的基本使用 练习:手机类与对象 内存图:一个对象 内存图:两个对象 内存图:同一个对象 局部变量与成员变量的区别 pr ...
- 有关最短路上的第k小/大值的总结
1.USACO08JAN Telephone Lines 题面 由于问的是最大值最小,所以二分加验证就好了 比较显然的,题干问的是第k+1长的路最短: 那么二分答案是正确的方向: 但是怎么验证? 我 ...
- vue : 无法加载文件 C:\Users\lihongjie\AppData\Roaming\npm\vue.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 htt ps:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。 所在位置 行:1 字符: 1 + vue init webpack vue_p
以管理员方式打开powershell 运行命令:set-ExecutionPolicy RemoteSigned 出现: 执行策略更改执行策略可帮助你防止执行不信任的脚本.更改执行策略可能会产生安全风 ...
- 搭建集群版Eureka Server
注册中心作为微服务架构中的核心功能,其重要性不言而喻.所以单机版的Eureka Server在可靠性上并不符合现在的互联网开发环境.集群版的Eureka Server才是商业开发中的选择. Eurek ...
- Java NIO浅析 转至 美团技术团队
出处: Java NIO浅析 NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服 ...
- Scala学习一——基础
一.使用Scala解释器 如果以命令行的方式运行,输出的结果会把类型带上,且结果名默认为res0递增.且Scala解释器读到一个解释器求值打印然后读取下一个(这个过程为读取-求值-打印-循环[REPL ...
- AGC009E Eternal Average
atc 神题orz 那个擦掉\(k\)个数然后写上一个平均值可以看成是\(k\)叉Huffman树的构造过程,每次选\(k\)个点合成一个新点,然后权值设为平均值.这些0和1都会在叶子的位置,同时每个 ...
- CF1151F Sonya and Informatics
cf luogu 我们最终要的序列一定是前面全是0,后面全是1,假设总共\(m\)个0,那么这等价于前\(m\)位0的个数为\(m\).当然一开始可能数量没有\(m\) 那就把前\(m\)位0的数量作 ...
- Redis从入门到高可用,分布式实践
redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...