CF1214
CF1214
C题WA3发的菜鸡还能涨分
A
发现货币面值都是倍数关系,直接暴力枚举第第一种换了多少个更新答案就好了
B
按照题意模拟
C
首先,左括号的数量不等于有括号的数量一定无解
想等的话在括号匹配的过程有在某一时刻栈中存在两个或者以上的右括号便无解
错误原因:思路出了点小问题
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 5e5 + 3;
char s[N];
int sta[N];
int n;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int sum1;
int tot;
int main(){
n = read();
scanf("%s",s + 1);
for(int i = 1;i <= n;++i)
sum1 += (s[i] == ')');
if(sum1 != n - sum1){printf("No\n");return 0;}
for(int i = 1;i <= n;++i){
if(s[i] == '(') tot++;
else{
tot--;
if(tot <= -2){printf("No\n");return 0;}
}
}
if(tot >= 2) printf("No\n");
else printf("Yes\n");
return 0;
}
D
我也不知道自己写了个什么算法,但是它过掉了
考虑这种情况
如图,如果黄色障碍点的话
绿色的点不管是不是障碍,都可以当做障碍去看
之后我们扩展一下
设\(dis_{x,y}\)表示把经过\((x,y)\)发出的路径全部搞死的最小代价
如果\((x,y)\)是空地并且\((x,y)\)和\((1,1)\)联通
\(dis_{x,y} = (dis_{x + 1,y} > 0 ) + (dis_{x,y + 1} > 0)\)
否则\(dis_{x,y} = 0\)
我们需要倒着这么转移
当然边界情况需要判断一下
之后我们就可以枚举所有的对角线的dis值之和
取个\(min\)
但是,答案如果涨这个样子怎么办
很明显我们只需要堵住一个格子
但是很明显答案不是对角线
想想我们\(dp\)的过程,我们已经把下面的贡献转移到了上面
所以他的dis数组是这样的,
\]
然后这样发现答案也是1
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 3;
string s[N];
bool book[N << 1];
int n,m;
int dis[N << 1];
int dx[2] = {0,1},dy[2] = {1,0};
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline int bfs(){
memset(book,0,sizeof(book));
book[0] = 1;
queue <int> q;q.push(0);
while(!q.empty()){
int k = q.front();q.pop();
int x = k / m,y = k % m;
for(int i = 0;i < 2;++i){
int xx = x + dx[i],yy = y + dy[i];
// if(book[]) continue;
if(xx < 0 || xx >= n || yy < 0 || yy >= m || book[xx * m + yy] || s[xx][yy] == '#') continue;
int z = xx * m + yy;
q.push(xx * m + yy);
book[xx * m + yy] = 1;
}
}
}
int sum[N << 1];
int main(){
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i = 0;i < n;++i) cin >> s[i];
memset(dis,0x3f,sizeof(dis));
for(int i = 0;i < n;++i){
for(int j = 0;j < m;++j)
if(s[i][j] == '#') dis[i * m + j] = 0;
}
bfs();
dis[n * m - 1] = 1;
for(int i = n - 1;i >= 0;--i){
for(int j = m - 1;j >= 0;--j){
int x = i * m + j;
if(s[i][j] == '#') continue;
if(!book[i * m + j]){dis[x] = 0;continue;}
if(i == n - 1 && j == m - 1) continue;
if(i == n - 1) dis[x] = (dis[x + 1] > 0);
else if(j == m - 1) dis[x] = (dis[x + m] > 0);
else dis[x] = (dis[x + 1] > 0) + (dis[x + m] > 0);
}
}
int ans = 2;
for(int i = 0;i < n;++i){
for(int j = 0;j < m;++j){
sum[i + j] += (dis[i * m + j] > 0);
}
}
for(int i = 1;i <= n + m - 2 - 1;++i) ans = min(ans,sum[i]);
// ans = min(ans,sum[1]);
printf("%d\n",ans);
return 0;
}
update:赛后被刁神吊打了Orz
这道题完全不需要这么麻烦
因为搜索出所有可能到达的点之后,维护两个指针
一个能向下走就向下走,另外一个能向右走就向右走
如果这两个路径有交点,那么一定是所有路径的必经点
直接把这个点删掉就好了QAQ
E
构造题
我们先把所有距离从大到小排序
因为题目保证有解
把所有的点对按照\(d\)排序之后,我们发现一个神奇的性质
对于排序完之后的数组的某一下标\(i\)
\(i + 1\)的距离在链上对应的点最大在\(i\)对应的点的右边
可能有些不好理解,结合图片理解一下
我们先构造一条这样的链
因为有距离\(d\)排完序之后不增的限制,所以\(i + 1\)对应为位置最多如图红色所示
这样我们暴力填上面的,对应的点就向这个样子挂下去
但是这样可能有个问题
如果上面的链的长度大于了\(n\)怎么办?
不用担心
每一个空点前面的点一定有儿子
因为有距离\(d\)的限制
所以我只直接把前面节点的儿子放到这个空点上就好了
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 3;
vector <int> G[N];
int ans[N];
int sum[N];
int tot;
int n;
struct node{
int id;
int val;
}a[N];
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline bool cmp(node x,node y){
return x.val > y.val;
}
int main(){
n = read();
for(int i = 1;i <= n;++i){
a[i].val = read();
a[i].id = i;
}
sort(a + 1,a + n + 1,cmp);
int len = 0;
for(int i = 1;i <= n;++i){
G[i + a[i].val - 1].push_back((a[i].id << 1) - 1);
sum[i] = a[i].id << 1;
len = max(len,i + a[i].val - 1);
}
for(int i = 1;i <= len;++i){
if(!sum[i]){
int x = G[i - 1].size();
sum[i] = G[i - 1][x - 1];
G[i - 1].pop_back();
}
}
for(int i = 1;i <= len;++i){
if(i != len) printf("%d %d\n",sum[i],sum[i + 1]);
for(int j = 0;j < (int)G[i].size();++j){
printf("%d %d\n",sum[i],G[i][j]);
}
}
return 0;
}
F
咕咕咕
经过\(smy\)和\(wqy\)的讲解之后,终于来补题了 QAQ
首先,我们需要证明,最佳答案的匹配一应不会覆盖整个环
考虑如果没有被覆盖的点,说明可能出现了下面的情况
红色的是同一类,黄色的同一类,最左右还有一个环没有画出来
你发现
把所有匹配的位置对应叮会更优(还有个环没画出来)
然后我们就可以枚举断点的位置
让所有的点都在这个位置一侧去匹配
我们想
枚举断点后断点左边的坐标要整体\(+m\)
对于一个人\(x_i\)和办公室\(y_i\)
他们匹配的代价是\(|x_i - y_i|\),
发现\(x_i\),和\(y_i\)的系数为\(1,-1\)
我们要求的实际上是
\]
\(a_i,b_i\)是他们贡献的系数
贡献的系数发现只取决于他是和左边的点匹配还是和右边的点去匹配
我们设\(d_i\)来表示这个东西
点上面的数就是他们\(d\)的值,然后我们发现,\(d >=0\)的坐标对答案的贡献都是\(-1\)
\(d < 0\)的坐标对答案啊的贡献都是\(1\)
这样的话,我们发现每一次枚举断点,消掉部分的会整体-1,对立部分整体+1
这个东西我们直接用指针去维护
维护到现在应该哪一部分的贡献将会改变
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 3;
const LL INF = 1e15;
struct node{
LL x;
int id;
int type;
}a[N];
int d[N];
LL _suma[N],_sumb[N];
LL *suma = _suma + 400000,*sumb = _sumb + 400000;
int n,m;
queue <int> q1,q2;
int as[N];
LL ans = INF,res;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline bool cmp(node xx,node yy){
return xx.x < yy.x;
}
int main(){
m = read(),n = read();
for(int i = 1;i <= n;++i){
a[i].x = read();
a[i].id = i;
a[i].type = 1;
}
for(int i = 1;i <= n;++i){
a[i + n].x = read();
a[i + n].id = i;
a[i + n].type = 2;
}
sort(a + 1,a + 2 * n + 1,cmp);
int na = 0,nb = 0;
for(int i = 1;i <= 2 * n;++i){
if(a[i].type == 1){
d[i] = na - nb;
suma[na - nb] += a[i].x;
na++;
}
else{
d[i] = nb - na;
sumb[nb - na] += a[i].x;
nb++;
}
}
int pos = 0;
for(int i = -n;i <= n;++i){
if(i >= 0) res -= suma[i] + sumb[i];
else res += suma[i] + sumb[i];
// printf("i:%d suma:%lld sumb:%lld\n",i,suma[i],sumb[i]);
}
// for(int i = 1;i <= 2 * n;++i) printf("%d\n",d[i]);
// printf("%d\n",res);
ans = res;
int ta = 0,tb = 0;
for(int i = 1;i <= 2 * n;++i){
// printf("%d %d %d\n",i,ta,tb);
if(a[i].type == 1){
res += suma[ta];
suma[d[i]] += m;
res += suma[ta];
ta++,tb--;
res -= sumb[tb] * 2;
}
else{
res += sumb[tb];
sumb[d[i]] += m;
res += sumb[tb];
ta--,tb++;
res -= suma[ta] * 2;
}
if(res < ans){
pos = i;
ans = res;
}
}
printf("%lld\n",ans);
for(int i = pos + 1;i <= 2 * n;++i){
if(a[i].type == 1){
if(!q2.empty()) as[a[i].id] = q2.front(),q2.pop();
else q1.push(a[i].id);
}
else{
if(!q1.empty()) as[q1.front()] = a[i].id,q1.pop();
else q2.push(a[i].id);
}
}
for(int i = 1;i <= pos;++i){
if(a[i].type == 1){
if(!q2.empty()) as[a[i].id] = q2.front(),q2.pop();
else q1.push(a[i].id);
}
else{
if(!q1.empty()) as[q1.front()] = a[i].id,q1.pop();
else q2.push(a[i].id);
}
}
for(int i = 1;i <= n;++i) printf("%d ",as[i]);
return 0;
}
CF1214的更多相关文章
- CF1214题解
D 因为可以用贡献2把起点终点堵掉,所以答案为0/1/2 0/2简单 1:方格可以理解为分层图,考虑每个能到达终点,起点能到达其的点,标记一下,对角线如果仅存在1则为必经之路 E \(d_i\le n ...
- 你还在为了JVM而烦恼么?(内存结构和垃圾回收算法)
做JAVA也有接近2年的时间了,公司的leader说,做JAVA,三年是个坎,如果过了三年你还没有去研究JVM的话,那么你这个程序员只能是板砖的工具了.恰逢辞职,来个JVM的解析可好? JVM是J ...
- VP记录
预计在最后的日子里适量VP 简单记录一下 CF 1037 Link 上来秒了ABCD,很快啊 A是二进制拆分,B是一眼贪心,C是一个非常简单且好写的dp D把边遍历顺序按照所需的bfs顺序排序,最后比 ...
随机推荐
- linux服务器配置防火墙使用端口
重启后生效方法: 1.开启: chkconfig iptables on 2.关闭: chkconfig iptables off 即时生效,重启后失效 : 1.开启: service iptabl ...
- 使用 Windows 10 WSL 搭建 ESP8266 编译环境并使用 VSCODE 编程(一)(2019-08-23)
目录 使用 Windows 10 WSL 搭建 ESP8266 编译环境并使用 VSCODE 编程 安装前准备 安装 ESP8266 工具链 下载 ESP8266 SDK 编译 花絮 使用 Windo ...
- phpmyadmin误删表后的恢复过程
转自:http://blog.csdn.net/ssrc0604hx/article/details/18717983 话说今天不知道是抽风了还是失魂了,在用phpmyadmin删除测试数据时,竟然将 ...
- JavaScript--查看代码运行效率console.time()与console.timeEnd()用法
程序运行时间计算: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- PHP Laravel系列之环境搭建( VirtualBox+Vagrant+Homestead+系列网址)
搭建环境从来都是阻挡一门新技能的最致命的硬伤,为了这个环境,我又是花费了半天的时间,各种问题层出不穷,下面基于网上的一些教程(我看到的都多少有些问题) 开始的时候是在实验楼这个平台上开始学习的,不过 ...
- javascript —— 禁止通过 Enter 键提交表单
$('btn').on('keydown', function () { return false; })
- 13条必知必会&&测试
1.13条必知必会 <> all(): 查询所有结果 <> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <> get(**kwargs) ...
- HLSL效果框架-多光源效果
原文:HLSL效果框架-多光源效果 昨日不可追, 今日尤可为.勤奋,炽诚,不忘初心 手机淘宝二维码 扫描 或者打开连接:程序设计开发 ,掌声鼓励,欢迎光临. 高级着色器语言(HLS ...
- ural 1519 Formula 1(插头dp)
1519. Formula 1 @ Timus Online Judge 干了一天啊!!!插头DP入门. 代码如下: #include <cstdio> #include <cstr ...
- MapReduce数据流-概述