Codeforces Round #394 (Div. 2) 题解
problem A
题目大意
已知有n个偶数,m个奇数,问这些数有没有可能组成一个严格递增1的序列
题解
判断abs(n,m) <= 1即可,注意n,m均为0的情况.
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
int main(){
int a,b;read(a);read(b);
printf(abs(a-b) <= 1 && !(a == 0 && b == 0) ? "YES" : "NO");
getchar();getchar();
return 0;
}
problem B
题目大意
在长度为m的圆形跑道上,起点不同的两个人逆时针沿跑道跑一圈,得到了每个人到它遇到的第1,2,...,n个障碍物的距离的数组。给出这两个数组,判断两个人是不是使用的一个跑道。(所有的跑道长度均为m,但不同跑道障碍物放置不同)
题解
我们要判断障碍物的放置是否相同
那么我们直接判断障碍物之间的间隔是否相同即可
由于这是个圆形跑道,所以数组[2,3,6]和[3,6,2]也是相同的
那么我们\(O(n^2)\)枚举即可
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 128;
int a1[maxn],a2[maxn],b1[maxn],b2[maxn];
int n;
inline int id(int x){
if(x > n) x -= n;
return x;
}
int main(){
int m;read(n);read(m);
for(int i=1;i<=n;++i) read(a1[i]);
for(int i=1;i<=n;++i) read(a2[i]);
for(int i=1;i<n;++i){
b1[i] = a1[i+1] - a1[i];
}b1[n] = m - (a1[n] - a1[1]);
for(int i=1;i<n;++i){
b2[i] = a2[i+1] - a2[i];
}b2[n] = m - (a2[n] - a2[1]);
//for(int i=1;i<=n;++i) printf("%d %d\n",b1[i],b2[i]);
bool flag = false;
for(int i=1,k;i<=n;++i){
for(int j=1;j<=n;++j){
if(b1[i] == b2[j]){
for(k=1;k<n;++k){
if(b1[id(i+k)] != b2[id(j+k)]) break;
}
if(k == n) flag = true;
}
}
}
if(flag) puts("YES");
else puts("NO");
getchar();getchar();
return 0;
}
Problem C
题目大意:
给定n个长度为m的环状字符串,每个字符串的首字符上有一个指针,每次操作可将任意一个指针左移或右移1.问最少移动多少次使得所有被指针指向的字符能构成一个合法的字符串。(合法:存在数字、小写字母,特殊符号)
题解:
读了半天没读懂题,看到样例解释才明白。
我们发现我们只用在意这三种东西的存在即可
而每个字符串中只有一个指针,也就是每个字符串中只能选择一个字符
所以至少选择3个字符串
那么我们\(O(n^3)\)枚举是哪三个字符串,并且每个字符串的指针应该指向什么
所以我们直接预处理一下每个字符串中指向每种字符的最小移动次数即可
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 64;
int a[maxn],b[maxn],c[maxn];
int main(){
int n,m;read(n);read(m);
char ch;
for(int i=1;i<=n;++i){
a[i] = b[i] = c[i] = 100000000;
for(int j=0;j<m;++j){
while(ch=getchar(),ch<'!');
if(ch >= '0' && ch <= '9') a[i] = cat_min(a[i],cat_min(j,m-j));
if(ch >= 'a' && ch <= 'z') b[i] = cat_min(b[i],cat_min(j,m-j));
if(ch == '*' || ch == '#' || ch == '&') c[i] = cat_min(c[i],cat_min(j,m-j));
}
}
int ans = 0x7f7f7f7f;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
for(int k=1;k<=n;++k){
if(i == j || j == k || i == k) continue;
ans = cat_min(ans,a[i] + b[j] + c[k]);
}
}
}
printf("%d\n",ans);
getchar();getchar();
return 0;
}
Problem D
题目大意
有三数组\(a,b,c\)有\(c_i = b_i - a_i\)满足\(c_i\)互不相同,且\(a_i,b_i \in [l,r]\).现在给定数组\(a\)和离散化后的\(c\),还原出任意一个可行的\(b\)数组.无解输出-1.
\(n \leq 10^5\)
题解
我们有\(c_i = b_i - a_i\)所以\(b_i = a_i + c_i\)
所以我们计算出\(b\)数组,再根据\(l\)的下边界调整,判断上边界是否超出即可
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 100010;
int a[maxn],b[maxn],c[maxn];
int main(){
int n,l,r;read(n);read(l);read(r);
for(int i=1;i<=n;++i) read(a[i]);
int maxx = -0x3f3f3f3f,minn = 0x3f3f3f3f;
for(int i=1;i<=n;++i){
read(c[i]);
b[i] = a[i] + c[i];
minn = cat_min(minn,b[i]);
maxx = cat_max(maxx,b[i]);
}
if(maxx - minn > r - l) return puts("-1");
int x = minn - l;
for(int i=1;i<=n;++i){
b[i] -= x;
printf("%d",b[i]);
if(i != n) putchar(' ');
else putchar('\n');
}
getchar();getchar();
return 0;
}
Problem E
题目大意
定义在笛卡尔坐标系中的一棵树:所有的节点都在不同的整点坐标上,所有的边都不重叠地平行于坐标轴上且边不可交叉。给定一棵n\((n \leq 30)\)个节点树,问它是否能转化成笛卡尔坐标系中的树。如果能则给出所有点的坐标,必须满足\(x_i,y_i \leq 10^{18}\)
题解
很明显,每个节点的度数不能超过4.
我们可以证明在坐标域为\([-10^{18},10^{18}]\)时只要满足度数要求,一定存在可行解。
很明显:现在最主要的是节点之间的间接冲突使得构造失败。
(如果你懂围棋的话,可以把出现冲突时的这种形状叫做愚形)
所以我们把节点之间的间距拉到足够大,使其不可能对彼此产生影响。
所以我们构造的前两个点的间距拉到\(2^{58}\)即可
然后每次构造下一个点的时候把间距变为原来的一半
这样即使中间再装下剩下的28个点也不会互相产生影响
这样构造即可
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 64;
int G[maxn][11],fa[maxn];
ll x[maxn],y[maxn];
int dx[] = {0,1,-1,0,0};
int dy[] = {0,0,0,1,-1};
inline int indx(int i){
if(i == 1) return 2;
if(i == 2) return 1;
if(i == 3) return 4;
if(i == 4) return 3;
}
void dfs(int u,ll d,int k){
for(int i=1;i<=G[u][0] && k;++i){
if(G[u][i] == fa[u]) swap(G[u][i],G[u][indx(k)]);
}
for(int i=1;i<=G[u][0];++i){
if(G[u][i] == fa[u]) continue;
x[G[u][i]] = x[u] + d*dx[i];
y[G[u][i]] = y[u] + d*dy[i];
fa[G[u][i]] = u;
dfs(G[u][i],d>>1,i);
}
}
int main(){
int n;read(n);
for(int i=1,u,v;i<n;++i){
read(u);read(v);
G[u][++G[u][0]] = v;if(G[u][0] == 5) return puts("NO");
G[v][++G[v][0]] = u;if(G[v][0] == 5) return puts("NO");
}
x[1] = y[1] = 0;fa[1] = 1;
dfs(1,1LL<<58,0);puts("YES");
for(int i=1;i<=n;++i) printf("%lld %lld\n",x[i],y[i]);
getchar();getchar();
return 0;
}
Problem F
题目大意
给定一个\(n*m\)的初始字符矩阵,有\(q\)次操作,每次操作在初始矩阵上把\((a_i,b_i)\)到\((c_i,d_i)\)之间的所有字符全部覆盖为\(c_i\)。两字符的距离定义为\(|ch_1-ch_2|\),矩阵的距离定义为对应字符距离之和。在所有操作产生的序列中取一个序列,使这个序列和其他序列的距离的总和最小。
\(n,m \leq 10^3 ; q \leq 3*10^5\)
题解
好麻烦啊这题。。真佩服在比赛中做出来的神犇们...
首先我们尝试枚举所求矩阵.
现在只要我们能在\(< O(n)\)的时间内求出答案即可.
这也能做?你是不是来搞笑的!
我们发现,这时我们可以再枚举一边所有的其它矩阵,挨个求距离
但是我们有两个性质没有利用
- 某一个范围内的所有字符全部相同
- 另一部分的字符完全是初始矩阵的字符
怎么利用这些性质呢?
我们可以想到分别处理出26个英文字母在所有操作产生的矩形内匹配时对距离总和做出的贡献
这样可以利用前缀和的方式O(26)计算第一条性质中表述的范围
但是我们预处理贡献时,算贡献应该和其他所有的操作产生的矩阵匹配
所以我们还应该预处理出在所有操作产生的的矩阵中某一个字母出现在某一点的次数
然后做前缀和也可以做到O(26)查询。
然后我们在处理出初始矩阵在所有操作产生的矩阵中的距离之和。
进行查询的时候,我们也需要减去我们当前枚举的操作矩阵对刚才的预处理值做出的贡献。
Code
代码注释:
\(f[i][j][k]\)为字母\(k\)出现在\((i,j)\)的次数的前缀和,程序中先是用二维差分处理了区间加法和单点求值,然后求前缀和还原了数组,然后再一次求前缀和实现区间查询。
\(num[i][j]\)为点\((i,j)\)被操作矩阵的字符覆盖的次数
\(g[i][j]\)为原序列\((i,j)\)和其他所有操作矩阵距离和,程序中求了前缀和.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline ll cat_max(const ll &a,const ll &b){return a>b ? a:b;}
inline ll cat_min(const ll &a,const ll &b){return a<b ? a:b;}
const int maxn = 1024;
const int maxm = 300010;
ll s[maxn][maxn],num[maxn][maxn];
ll g[maxn][maxn];
ll f[maxn][maxn][28];
struct Node{
ll x1,y1,x2,y2;
int ch;
}a[maxm];
ll sum = 0;
int main(){
int n,m,q;read(n);read(m);read(q);
char ch;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
while(ch=getchar(),ch<'!');
s[i][j] = ch - 'a';
}
}
for(int i=1;i<=q;++i){
read(a[i].x1);read(a[i].y1);
read(a[i].x2);read(a[i].y2);
while(ch=getchar(),ch<'!');
a[i].ch = ch - 'a';
f[a[i].x1][a[i].y1][a[i].ch]++;
f[a[i].x2+1][a[i].y1][a[i].ch]--;
f[a[i].x1][a[i].y2+1][a[i].ch]--;
f[a[i].x2+1][a[i].y2+1][a[i].ch]++;
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
for(int k=0;k<26;++k){
f[i][j][k] += f[i-1][j][k] + f[i][j-1][k] - f[i-1][j-1][k];
num[i][j] += f[i][j][k];
}
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
f[i][j][s[i][j]] += q - num[i][j];
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
for(int k=0;k<26;++k){
g[i][j] += f[i][j][k]*abs(s[i][j] - k);
}sum += g[i][j];
}
}
//printf("%lld\n",sum);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
for(int k=0;k<26;++k){
f[i][j][k] += f[i-1][j][k] + f[i][j-1][k] - f[i-1][j-1][k];
}g[i][j] += g[i-1][j] + g[i][j-1] - g[i-1][j-1];
}
}
ll ans = 1LL<<60;
for(int i=1;i<=q;++i){
ll nw = sum;
for(int k=0;k<26;++k){
nw += abs(k - a[i].ch)*(f[a[i].x2][a[i].y2][k] - f[a[i].x1-1][a[i].y2][k] - f[a[i].x2][a[i].y1-1][k] + f[a[i].x1-1][a[i].y1-1][k]);
}nw -= (g[a[i].x2][a[i].y2] - g[a[i].x1-1][a[i].y2] - g[a[i].x2][a[i].y1-1] + g[a[i].x1-1][a[i].y1-1]);
ans = min(ans,nw);
}printf("%I64d",ans);
getchar();getchar();
return 0;
}
Codeforces Round #394 (Div. 2) 题解的更多相关文章
- Codeforces Round #182 (Div. 1)题解【ABCD】
Codeforces Round #182 (Div. 1)题解 A题:Yaroslav and Sequence1 题意: 给你\(2*n+1\)个元素,你每次可以进行无数种操作,每次操作必须选择其 ...
- Codeforces Round #394 (Div. 2) E. Dasha and Puzzle(分形)
E. Dasha and Puzzle time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- Codeforces Round #608 (Div. 2) 题解
目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 ...
- Codeforces Round #525 (Div. 2)题解
Codeforces Round #525 (Div. 2)题解 题解 CF1088A [Ehab and another construction problem] 依据题意枚举即可 # inclu ...
- Codeforces Round #528 (Div. 2)题解
Codeforces Round #528 (Div. 2)题解 A. Right-Left Cipher 很明显这道题按题意逆序解码即可 Code: # include <bits/stdc+ ...
- Codeforces Round #466 (Div. 2) 题解940A 940B 940C 940D 940E 940F
Codeforces Round #466 (Div. 2) 题解 A.Points on the line 题目大意: 给你一个数列,定义数列的权值为最大值减去最小值,问最少删除几个数,使得数列的权 ...
- Codeforces Round #677 (Div. 3) 题解
Codeforces Round #677 (Div. 3) 题解 A. Boring Apartments 题目 题解 简单签到题,直接数,小于这个数的\(+10\). 代码 #include &l ...
- Codeforces Round #665 (Div. 2) 题解
Codeforces Round #665 (Div. 2) 题解 写得有点晚了,估计都官方题解看完切掉了,没人看我的了qaq. 目录 Codeforces Round #665 (Div. 2) 题 ...
- Codeforces Round #160 (Div. 1) 题解【ABCD】
Codeforces Round #160 (Div. 1) A - Maxim and Discounts 题意 给你n个折扣,m个物品,每个折扣都可以使用无限次,每次你使用第i个折扣的时候,你必须 ...
随机推荐
- 杂谈:HTML 5的消息通知机制
译文来源:http://www.ido321.com/1130.html 原文:HTML 5 Notification 译文:HTML 5 的消息通知机制 译者:dwqs watermark/2/te ...
- 安装部署zookeeper集群
实验说明: 三台虚拟机做zookeeper集群,集群个数最好是奇数个,原理详见zookeeper 详解 安装zookeeper 请确保jdk 已安装好,否则无法启动 三台虚拟机IP分别为:192. ...
- JavaScript -- JavaScript DOM 编程艺术(第2版)
/* 渐进增强 平稳退化 网页 结构层(structural layer): HTML 表示层(presentation layer): CSS <link rel="styleshe ...
- PowerBuilder -- Tab控件
在tab中关闭窗口 Close(tab_1.getparent()) 调整tab中的控件的tab oder 鼠标右键tabpage_1,选择 Tab Order菜单.
- Android-自定义广播不能用的可能的原因(sendbroadcast 不起效果)
参考博客:https://blog.csdn.net/chuyouyinghe/article/details/79424373 照着书上的源码将程序原封不动敲了一遍,但发现这特么怎么也收不到发出的广 ...
- iOS 10 的杂碎资料
兼容iOS 10 资料整理笔记 1.Notification(通知) 自从Notification被引入之后,苹果就不断的更新优化,但这些更新优化只是小打小闹,直至现在iOS 10开始真正的进行大 ...
- springcloud和kubernetes对比
由于这两个都不熟,所以在考虑学哪个. 先说结论:都要学,但是重点学k8s,k8s是一个更加完善的解决方案,springcloud被淘汰只是时间的问题. 从自己的经历和网上的文章两方面分析 个人经历: ...
- log4j方法的使用
log4j.properties配置 log4j.logger.webAplLogger=info, logFile log4j.appender.logFile=org.apache.log4j.F ...
- 操作符表示指针指向的底层值 切片 nill 清空 按值引用赋值 获取地址赋值
package main import "fmt" var thisVisitedUrls [] string func tf() { p := &thisVisitedU ...
- 经常遇到js的面试题
大家都知道在面试的时候,很多前端的必须要问的就是js的问题,最近我们公司也有很多这样的面试,我提了一些个问题,还有我面试的时候面试官面试我的问题汇总,也有百度的别人的,希望对那些刚进入这个行业的有一些 ...