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顺序排序,最后比 ... 
随机推荐
- “龙井”开箱评测 |Alibaba Dragonwell 新手上路指南
			作者|阿里云智能事业群 高级技术专家 陆传胜 阿里巴巴有着最丰富的 Java 应用场景,覆盖电商,金融,物流等众多领域,是世界上最大的 Java 用户之一. 2019 年 3 月 21 日,阿里巴巴在 ... 
- 洛谷P1879 玉米田
			题目描述 农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地.John打算在牧场上的某几格里种上美味的草,供他 ... 
- hdu 1728 逃离迷宫 BFS加优先队列 DFS()
			http://acm.hdu.edu.cn/showproblem.php?pid=1728 题意就是能否在规定的转弯次数内从起点走到终点.刚走时那步方向不算. 只会bfs(),但想到这题需要记录转弯 ... 
- WinMail邮件服务器(客户端)环境搭建与配置
			WinMail邮件服务器(客户端)环境搭建与配置 一.在搭建WinMail邮件服务器(客户端)之前必备 (1).在虚拟机上安装两个干净无毒的操作系统 ... 
- 从零学React Native之08Image组件
			开发过程中, 几乎每个项目都会用到图片. RN就是通过Image组件显示图片.既可以加载网络图片,也可以加载本地资源图片. Image组件必须在样式中声明图片的款和高.如果没有声明,则图片将不会被呈现 ... 
- Python 变量赋值
- FastReport模板设计和调用
			FastReport是功能齐全的报表控件,使开发者可以快速并高效地为·NET/VCL/COM/ActiveX应用程序添加报表支持.最近一个项目就涉及到了FastReport报表的应用.这里简单记录下( ... 
- php 正则表达式怎么匹配标签里面的style?
			$str = '<div style="margin:0px;text-align:left;padding:0px;">任意内容</div>'; $reg ... 
- Mysql 锁表处理
			-- 查看正在被锁定的的表 show ; -- 查看进程号 show processlist; -- 杀掉进程 : -- 表级锁次数 show status like 'Table%'; +----- ... 
- H3C ICMP
