首页 > 其他分享 >2022CSP-J线上游记

2022CSP-J线上游记

时间:2023-01-07 20:12:26浏览次数:61  
标签:ch return int expr else 2022CSP 线上 游记 op

写在前面

安徽CSP取消了……

去年CSP考炸的我本来想今年一雪前耻(bushi),结果……

T1

第一题大毒瘤!
首先观察数据可以分类如下两种情况:

  1. \(a = 1\)
    直接输出\(1\),return 0
  2. \(a \le 2\)
    模拟乘方,由于不能超过\(10^9\),开long long模拟就可以过。

\(Code:\)

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
long long a, b, ans = 1;
int main()
{
	freopen("pow.in","r",stdin);
	freopen("pow.out","w",stdout);
	cin >> a >> b;
	if(a == 1) {
		cout << 1;
		return 0;
	}
	for (int i = 1; i <= b; i++) {
		ans *= a;
		if(ans > 1000000000) {
			cout << -1;
			return 0;
		}
	}
	cout << ans;
}

T2

去年T2是大模拟题,但是我炸了……

在家写代码的时候就谨慎得多。

分析题面可知\(e \times d = pq - p - q + 2\)

\(\therefore m = n - e \times d + 2 = p + q\)

\(\therefore n = p(m - p) = mp - p^2\)

\(\therefore p^2 - mp + n = 0\)

\(\because p \leq q\)

\(\therefore p = \frac{m-\sqrt{m^2-4\times n}}{2}\)

这也就是说,这道题变成了裸的解方程!

求整数解需要有如下条件

  1. \(m^2 - 4 \times n\)是完全平方数
  2. \(m-\sqrt{m^2 - 4 \times n}\)是偶数

\(Code:\)

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
int k;
long long n, e, d, m;
int main()
{
	freopen("decode.in","r",stdin);
	freopen("decode.out","w",stdout);
	scanf("%d", &k);
	while (k--) {
		scanf("%lld%lld%lld",&n, &e, &d);
		m = n - e * d + 2;
		long long sqr = sqrt(m * m - 4 * n);
		if(sqr * sqr != m * m - 4 * n) {
			printf("NO\n");
			continue;
		}
		if((m - sqr) % 2 == 1) {
			printf("NO\n");
			continue;
		}		
		long long p = (m - sqr) / 2 , q = (m + sqr) / 2;
		printf("%lld %lld\n", p, q);
	} 
}

T3

前置知识1:栈

oiwiki

前置知识2:表达式求值——中缀表达式

我们需要一个数值栈d以及符号栈op

从左向右扫描表达式字符串(以本题的逻辑运算为例)
当扫到数字01时,直接加入数值栈。

当扫到符号时,分为一下三种情况:

  1. (

直接入符号栈

  1. 不是括号

如果符号栈非空且符号栈栈顶的优先级大于当前符号优先级,则进行calc运算;

否则把当前符号入栈。

  1. )

如果符号栈栈顶不是(,则进行calc运算,知道栈顶是(为止,并将(弹出。

calc运算步骤如下

定义ch是符号栈栈顶符号,符号栈pop

定义y是数值栈栈顶符号,数值栈pop

定义x是数值栈栈顶符号,数值栈pop

xy执行ch操作,并将结果压进数值栈。

扫描结束后,如果符号栈非空,则进行calc操作至符号栈为空为止。

\(Code:\)

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
string expr;//表达式 
stack<int>d;//数值栈 
stack<char>op;//符号栈 
int level(char ch) { //判断符号优先级 
	if(ch == '&') return 2;
	else if(ch == '|') return 1;
	else return 0; //括号优先级最低 
}
void calc() { //calc操作 
	int y = d.top(); d.pop();
	int x = d.top(); d.pop();
	char ch = op.top(); op.pop();
	if(ch == '&') d.push(x & y);
	else d.push(x | y);
}
int main()
{
	cin >> expr;
	for (int i = 0; i < expr.size(); i++) { //从左往右扫描表达式 
		if (expr[i] == 0 || expr[i] == 1) {
			d.push(expr[i] - '0');//压入数值栈 
		}
		else if (expr[i] == '(') op.push('(');//直接压入
		else if (expr[i] != ')'){
			while(!op.empty() && level(op.top()) >= level(expr[i])) calc();//运算优先级高的表达式 
			op.push(expr[i]);
		}
		else {
			while(op.top() != '(') calc();//处理括号
			op.pop(); 
		}
	}
	while(!op.empty()) calc();//处理剩余表达式
	cout << d.top(); 
}


前置知识3:表达树

表达式1&0|0&(0|1)的表达树如下:

     |
    / \
   /   \
  /     \
  &     |
 / \   / \
/   \ /   \
1   0 0	  |
         / \
        /   \
        0   1

我们可以看到,最早运算的运算符深度越深,且如果一个符号左边先算的式子就是该符号的左子树,右边先算的式子就是该符号的右子树,数字没有子节点。

建树过程与表达式求值类似。

\(Code:\)

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
const int N = 1E6 + 5;
string expr;
stack<int>d, op;
int num(char ch){
	if(ch == '&') return 3;
	else if(ch == '|') return 2;
	else if(ch == '1') return 1;
	else if(ch == '0') return 0;
}
void build() {
	int y = d.top();d.pop();
	int x = d.top();d.pop();
	int ch = op.top();op.pop();
	l[ch] = x, r[ch] = y;
	d.push(ch);
}
int main()
{
	cin >> expr;
	for (int i = 0; i < expr.size(); i++) {
		dat[i + 1] = num(expr[i]);
		if(expr[i] == '0' || expr[i] == '1') {
			d.push(i + 1);
		}
		else if(expr[i] == '(') op.push(-1);
		else if(expr[i] != ')'){
			while(!op.empty() && dat[op.top()] >= dat[i + 1]) build();
			op.push(i + 1);
		}
		else {
			while(op.top() != -1) build();
			op.pop();
		}
	}
	while(!op.empty()) build();
}

回归本题

本题最后就是在表达树上进行\(dfs\),当左节点的表达式的值可以“垄断”右边表达式的值时,右边的就不需要进行“垄断”操作的计算。

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
const int N = 1E6 + 5;
int l[N], r[N], dat[N], root;
int And, Or;
bool vis[N];
string expr;
stack<int>d, op;
int num(char ch){
	if(ch == '&') return 3;
	else if(ch == '|') return 2;
	else if(ch == '1') return 1;
	else if(ch == '0') return 0;
	return -1;
}
void build() {
	int y = d.top();d.pop();
	int x = d.top();d.pop();
	int ch = op.top();op.pop();
	l[ch] = x, r[ch] = y;
	d.push(ch);
}
int dfs(int u, int &And, int &Or) {
	if(dat[u] < 2) return dat[u];
	int L = dfs(l[u], And, Or);
	if(dat[u] == 3 && L == 0) {
		And += 1;
		return 0;
	}
	else if(dat[u] == 2 && L == 1) {
		Or += 1;
		return 1;
	}
	int R = dfs(r[u], And, Or);
	if(dat[u] == 3) return L & R;
	else return L | R; 
}
int main()
{
	freopen("expr.in","r",stdin);
	freopen("expr.out","w",stdout);
	cin >> expr;
	for (int i = 0; i < expr.size(); i++) {
		dat[i + 1] = num(expr[i]);
		if(expr[i] == '0' || expr[i] == '1') {
			d.push(i + 1);
		}
		else if(expr[i] == '(') op.push(-1);
		else if(expr[i] != ')'){
			while(!op.empty() && dat[op.top()] >= dat[i + 1]) build();
			op.push(i + 1);
		}
		else {
			while(op.top() != -1) build();
			op.pop();
		}
	}
	while(!op.empty()) build();
	root = d.top();
	for (int i = 1; i <= expr.size(); i++) {
		vis[l[i]] = vis[r[i]] = 1;
		if(!l[i] && !r[i]) vis[i] = 1;
	}
	cout << dfs(root, And, Or) <<'\n';
	cout << And << ' ' << Or;
}

T4

很明显,是\(dp\)。
首先按\(x_i\)为第一关键字,\(y_i\)为第二关键字从小到大排序。

接下来我们定义状态\(dp_{i,j}\),表示前\(i\)添加\(j\)个点后,最多能连接起多少个点,不包括后来添加的\(k\)个点。

则\(\max\{dp_{i,j}\}+k\)即为最大值,因为一定可以取完\(k\)个点。

状态转移方程:\(dp_{i,j} = \max\limits_{1\leq l \leq i}\{dp_{l,j-(x_i+y_i-x_l-y_l-1)}\}+1\)

\(Code:\)

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
int n, k, dp[505][105], ans;
struct Pos{
	int x, y;
}a[505];
bool cmp(const Pos& u, const Pos& v) {
	return u.x < v.x || u.x == v.x && u.y < v.y;
}
int main()
{
	freopen("point.in","r",stdin);
	freopen("point.out","w",stdout);
	cin >> n >> k;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].x >> a[i].y;
	}
	stable_sort(a + 1, a + n + 1, cmp);
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j <= k; j++) dp[i][j] = 1;
		for (int j = 1; j < i; j++) {
			if(a[j].y > a[i].y) continue;
			int s = a[i].x + a[i].y - a[j].x - a[j].y - 1;
			for(int l = s; l <= k; l++) {
				dp[i][l] = max(dp[i][l], dp[j][l - s] + 1);
			}
		}
		ans = max(ans, dp[i][k]);
	}
	cout << ans + k;
}


标签:ch,return,int,expr,else,2022CSP,线上,游记,op
From: https://www.cnblogs.com/easonhe/p/2022CSP-J.html

相关文章

  • 问诊”互联网医院:线上就诊医保支付“卡”在哪儿?
    对患者而言,除了诊疗质量外,互联网医院服务与医保的衔接至关重要。相关政策鼓励互联网医院落实医保支付,但实际推进效果有限,医保支付仍是很多互联网医院需要打通的“堵点”。......
  • 本地环境与线上服务Docker的问题
    一、环境相关一般来说,环境最重要,尤其是本地和线上环境的差异。可能会存在线上显卡算力太高,与本地显卡相关框架不匹配;比如:线上显卡:NVIDIAA10,算力8.6,则需要CUDA版本:建议C......
  • 前端线上图片生成马赛克
    前言说起图片的马赛克,可能一般都是由后端实现然后传递图片到前端,但是前端也是可以通过canvas来为图片加上马赛克的,下面就通过码上掘金来进行一个简单的实现。实现markup<img......
  • 【线上问题】Tomcat部分接口偶发出现请求时间过长问题排查
    参考资料​​tomcat响应过慢——解决办法-CodingPanda​​服务器处理客户端请求线程只升不降问题分析总结_cuidongdong1234的博客_服务线程数不降怎么回事​​​​线程数......
  • 【线上实习项目】助力你的校招!
    ​【线上实习项目】助力你的校招!​23届正式秋招快要结束,可在写简历的时候,无论多努力也憋不出来一个像样的实习经历,又不敢造假,经历真实与否,HR一问就会露馅。该怎样充实自己的......
  • 如何实现线上线下良好互通?华为云CC支持一点接入多点通达
    随着数字经济和互联网的发展,企业业务覆盖范围逐渐扩大,比如我们熟悉的连锁餐饮、服饰以及物流公司等,分店或者分销点几乎遍布了各大城市。而业务的迅速扩张也给企业的管理带去......
  • 如何定位线上问题?
    面试官:「你是怎么定位线上问题的?」这个面试题我在两年社招的时候遇到过,前几天面试也遇到了。我觉得我每一次都答得中规中矩,今天来梳理复盘下,下次又被问到的时候希望可以答得......
  • NOIP2022 游记
    \[\mathcal{I\;\,COME\;\,FROM\;\,THE\;\,SKY}\]\[\mathcal{BORNE\;\,WITH\;\,THE\;\,WINDS\;\,OF\;\,FATE}\]\[\mathcal{I\;\,CAST\;\,OFF\;\,MY\;\,CAGE}\]\[\mathcal......
  • 网页设计与制作期末大作业报告——大学生线上花店
    《网页设计与制作》大作业报告学院:**学院姓名:学号:专业:摘要:摘要:2018年,大学毕业的李强回到家乡鹤壁创办了名为“初心花店”的线上平台,提起创业的初衷,李强直言“就是希望通过......
  • 010 、JVM实战总结: 动手实验:亲自感受一下线上系统部署时如何设置JVM内存大小
     1、前文回顾      新生代里内存不够了,就会触发一次MinorGC,当他成为是十多岁的“老年人”的时候,就会被转移到老年代里去跟JVM内存相关的几个核心参数图解-Xms:Java......