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个折扣的时候,你必须 ...
随机推荐
- Hibernate “N+1”查询问题
Hibernate 默认情况下使用立即检索策略,即从数据库加载A对象时 会同时加载跟它关联的B,这样产生了不必要的对象集合查询,而且本来可以合并的sql要执行1+N次,因为一条select出所有的A ...
- mysql忘记password
有时候突然忘记MySQL的password会真的不爽,这里介绍一种MySQLpassword忘记时重置password的方法,操作系统win8,MySql version:5.6.10 1 在任务管理 ...
- ubantu 下 修改mysql 默认编码
启动mysql后,以root登录mysql root@Eadgar-virtual-machine:~# mysql -uroot -proot mysql> show variables li ...
- 过滤XSS的HTMLPurifier使用
什么是HTMLPurifier? 在php里解决XSS最简单的方法是使用htmlspecialchars转义xml实体,但对于需要使用xml的时候就搏手无策了. HTML Purifier是基于php ...
- 在一个JS文件中引用另一个JS文件
方法一,在调用文件的顶部加入下例代码: document.write(”<script language=javascript src=’/js/import.js’></scrip ...
- Druid——阿里巴巴的开源项目(关于数据库连接、监控)
相关文章 0.Druid首页——jdbc连接池,监控组件 1.阿里巴巴的开源项目Druid(关于数据库连接) 2.ITeye谈Druid 3.DBCP(DataBase connection pool ...
- Mybatis之基本简介
一.Mybatis简介 MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架.MyBatis 摒除了大部分的JDBC代码.手工设置参数和结果集重获.MyBatis 只使用简单的XML ...
- 九度OJ 1168:字符串的查找删除 (查找)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:4276 解决:1699 题目描述: 给定一个短字符串(不含空格),再给定若干字符串,在这些字符串中删除所含有的短字符串. 输入: 输入只有1 ...
- 用于string对象中字符截取的几种函数总结——语法、参数意义及用途举例
1. charAt():返回指定位置的字符. 语法:stringObject.charAt(index) 参数意义:index 必需,指字符在字符串中的下标.需要注意的是,字符串中第一个字符的下标是 ...
- [IR课程笔记]Web search
一. 搜索引擎 组成部分: 1. 网络爬虫(web crawler) 2. 索引系统(indexing system) 3. 搜索系统 (searching system) consideratio ...