小文同学刚刚接触了信息学竞赛,有一天她遇到了这样一个题:给定正整数
“简单!”小文心想,同时很快就写出了一份程序,可是测试时却出现了错误。
小文很快意识到,她的程序里的变量都是 int
类型的。在大多数机器上,int
类型能表示的最大数为
由于小文刚刚学会编程,她担心使用 int
计算会出现问题。因此她希望你在 -1
进行警示,否则就输出正确的
然而小文还是不知道怎么实现这份程序,因此她想请你帮忙。
输入共一行,两个正整数
输出共一行,如果 -1
。
10 9
1000000000
23333 66666
-1
对于
对于
对于
对于
签到题。进行计算 long long
即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10;
long long a, b, c;
int main() {
scanf("%lld%lld", &a, &b);
if (a == 1) {
printf("1\n");
return 0;
}
c = 1;
for (int i = 1; i <= b; i++) {
c *= a;
if (c > 1e9) {
printf("-1\n");
return 0;
}
}
printf("%lld\n", c);
return 0;
}
给定一个正整数
第一行一个正整数
接下来
输出
为使输出统一,你应当保证
如果无解,请输出 NO
。
10
770 77 5
633 1 211
545 1 499
683 3 227
858 3 257
723 37 13
572 26 11
867 17 17
829 3 263
528 4 109
2 385
NO
NO
NO
11 78
3 241
2 286
NO
NO
6 88
【样例 #2】
见附件中的 decode/decode2.in
与 decode/decode2.ans
。
【样例 #3】
见附件中的 decode/decode3.in
与 decode/decode3.ans
。
【样例 #4】
见附件中的 decode/decode4.in
与 decode/decode4.ans
。
【数据范围】
以下记
保证对于
测试点编号 | 特殊性质 | |||
---|---|---|---|---|
保证有解 | ||||
无 | ||||
保证有解 | ||||
无 | ||||
保证有解 | ||||
无 | ||||
保证若有解则 |
||||
保证有解 | ||||
无 | ||||
无 |
很多大佬都用的数学方法,但其实这道题没有这么复杂。
对于每次询问,需要求出两个正整数
显然
考虑二分枚举
设
所以
注意初始右区间端点不可为
不难发现需要二分的区间
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int Q;
long long n, e, d;
bool binary_search() {
long long k = n + 2 - e * d;
long long l = 1, r = k - 1;
bool flag = 0;
while (l <= r) {
long long p = (l + r) >> 1;
long long q = k - p;
if (p * q < n) {
l = p + 1;
} else if (p * q > n) {
r = p - 1;
} else {
printf("%lld %lld\n", p, q);
flag = 1;
break;
}
}
return flag;
}
int main() {
scanf("%d", &Q);
while (Q--) {
scanf("%lld%lld%lld", &n, &e, &d);
bool flag = binary_search();
if (!flag) {
printf("NO\n");
}
}
return 0;
}
逻辑表达式是计算机科学中的重要概念和工具,包含逻辑值、逻辑运算、逻辑运算优先级等内容。
在一个逻辑表达式中,元素的值只有两种可能:&
)和“或”(符号为 |
)。其运算规则如下:
在一个逻辑表达式中还可能有括号。规定在运算时,括号内的部分先运算;两种运算并列时,&
运算优先于 |
运算;同种运算并列时,从左向右运算。
比如,表达式 0|1&0
的运算顺序等同于 0|(1&0)
;表达式 0&1&0|1
的运算顺序等同于 ((0&1)&0)|1
。
此外,在 C++ 等语言的有些编译器中,对逻辑表达式的计算会采用一种“短路”的策略:在形如 a&b
的逻辑表达式中,会先计算 a
部分的值,如果 b
部分的值;同理,在形如 a|b
的逻辑表达式中,会先计算 a
部分的值,如果 b
部分的值。
现在给你一个逻辑表达式,你需要计算出它的值,并且统计出在计算过程中,两种类型的“短路”各出现了多少次。需要注意的是,如果某处“短路”包含在更外层被“短路”的部分内则不被统计,如表达式 1|(0&1)
中,尽管 0&1
是一处“短路”,但由于外层的 1|(0&1)
本身就是一处“短路”,无需再计算 0&1
部分的值,因此不应当把这里的 0&1
计入一处“短路”。
输入共一行,一个非空字符串
输出共两行,第一行输出一个字符 0
或 1
,表示这个逻辑表达式的值;第二行输出两个非负整数,分别表示计算上述逻辑表达式的过程中,形如 a&b
和 a|b
的“短路”各出现了多少次。
0&(1|0)|(1|1|1&0)
1
1 2
(0|1&0|1|1|(1|1))&(0&1&(1|0)|0|1|0)&0
0
2 3
【样例解释 #1】
该逻辑表达式的计算过程如下,每一行的注释表示上一行计算的过程:
0&(1|0)|(1|1|1&0)
=(0&(1|0))|((1|1)|(1&0)) //用括号标明计算顺序
=0|((1|1)|(1&0)) //先计算最左侧的 &,是一次形如 a&b 的“短路”
=0|(1|(1&0)) //再计算中间的 |,是一次形如 a|b 的“短路”
=0|1 //再计算中间的 |,是一次形如 a|b 的“短路”
=1
【样例 #3】
见附件中的 expr/expr3.in
与 expr/expr3.ans
。
【样例 #4】
见附件中的 expr/expr4.in
与 expr/expr4.ans
。
【数据范围】
设
对于所有数据,0
、1
、&
、|
、(
、)
且是一个符合规范的逻辑表达式。保证输入字符串的开头、中间和结尾均无额外的空格。保证 ((a))
形式的子串,其中 a
是符合规范的逻辑表
达式)。
测试点编号 | 特殊条件 | |
---|---|---|
无 | ||
无 | ||
1 | ||
2 | ||
3 | ||
无 | ||
1 | ||
2 | ||
3 | ||
无 |
其中:
特殊性质 1 为:保证 &
。
特殊性质 2 为:保证 |
。
特殊性质 3 为:保证 (
和 )
。
【提示】
以下给出一个“符合规范的逻辑表达式”的形式化定义:
0
和 1
是符合规范的;s
是符合规范的,且 s
不是形如 (t)
的字符串(其中 t
是符合规范的),那么字符串 (s)
也是符合规范的;a
和 b
均是符合规范的,那么字符串 a&b
、a|b
均是符合规范的;不难发现这又是一道继承了去年普及 T3 的大模拟。与 CSP-J 2020 T3 类似,考虑采用计算后缀表达式的方式。
这样,题目就转化为了:
至于题目中所求的短路次数,在运算时进行标记即可。
对于问题 (1) ,我们可以考虑维护两个栈,运算符栈
具体操作流程如下:
(
,则直接将其压入 )
,则依次弹出 (
;1
、0
,则直接压入 &
、|
,则依次弹出 特别地,我们规定左括号的优先级最低,即在情况 (4) 中无论何时左括号都不会被压入
对于问题 (2) ,我们仍然考虑维护一个临时栈
1
、0
,则直接压入 &
、|
,则依次从 &
,则:
0
,则发生短路,将运算结果 0
压入 1
,则没有发生短路,运算结果记为 l & r
,并将运算结果压入 |
,则:
0
,则没有发生短路,运算结果记为 l | r
,并将运算结果压入 1
,则发生短路,将运算结果 1
压入 此时,结果即为
维护时需要注意不可使用 STL 自带 stack
,因为 stack
不支持随机访问,需要自行手写。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
const int N = 1e6 + 10;
template<typename T>
struct Stack {
T val[N];
int stackTop = 0;
void push(T x) {
val[++stackTop] = x;
}
T pop() {
return val[stackTop--];
}
T top() {
return val[stackTop];
}
bool empty() {
return stackTop == 0;
}
int size() {
return stackTop;
}
};
struct Node {
bool val;
int or_, and_;
Node() {}
Node(bool _val) {
val = _val;
or_ = 0, and_ = 0;
}
Node(bool _val, int _or_, int _and_) {
val = _val, or_ = _or_, and_ = _and_;
}
};
int priority(char op) {
if (op == '&') return 2;
if (op == '|') return 1;
return 0;
}
Stack<char> op, res;
auto midToSuffix(string s) {
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') {
op.push(s[i]);
} else if (s[i] == ')') {
while (!op.empty()) {
if (op.top() == '(') {
op.pop();
break;
}
int cur = op.top();
res.push(cur);
op.pop();
}
} else if (s[i] == '0' || s[i] == '1') {
res.push(s[i]);
} else if (s[i] == '&' || s[i] == '|') {
while (!op.empty()) {
if (priority(op.top()) >= priority(s[i])) {
res.push(op.top());
op.pop();
} else {
break;
}
}
op.push(s[i]);
}
}
while (!op.empty()) {
res.push(op.top());
op.pop();
}
return res;
}
Stack<Node> tmp;
auto calcSuffix(Stack<char> suffix) {
for (int i = 1; i <= suffix.size(); i++) {
char val = suffix.val[i];
if (val == '0' || val == '1') {
tmp.push(Node(val - '0'));
} else if (val == '&') {
Node r = tmp.top();
tmp.pop();
Node l = tmp.top();
tmp.pop();
if (l.val == 0) {
tmp.push(Node(0, l.or_, l.and_ + 1));
} else {
tmp.push(Node(l.val & r.val, l.or_ + r.or_, l.and_ + r.and_));
}
} else if (val == '|') {
Node r = tmp.top();
tmp.pop();
Node l = tmp.top();
tmp.pop();
if (l.val == 1) {
tmp.push(Node(1, l.or_ + 1, l.and_));
} else {
tmp.push(Node(l.val | r.val, l.or_ + r.or_, l.and_ + r.and_));
}
}
}
return tmp.top();
}
int main() {
string s;
cin >> s;
auto suffix = midToSuffix(s);
auto root = calcSuffix(suffix);
cout << root.val << endl << root.and_ << ' ' << root.or_ << endl;
return 0;
}
在一个二维平面内,给定
你在自由添加
第一行两个正整数
接下来
输出一个整数表示满足要求的序列的最大长度。
8 2
3 1
3 2
3 3
3 6
1 2
2 2
5 5
5 3
8
4 100
10 10
15 25
20 20
30 30
103
【样例 #3】
见附件中的 point/point3.in
与 point/point3.ans
。
第三个样例满足
【样例 #4】
见附件中的 point/point4.in
与 point/point4.ans
。
【数据范围】
保证对于所有数据满足:
测试点编号 | |||
---|---|---|---|
不难发现这是一道 DP 题。 但是由于本人太弱,此处仅介绍
发现对于测试点
显然在这种情况下,从
每次选择一个点
再次观察数据,发现对于测试点
记状态
答案即为转移过程中
这样,我们将两种策略组合便获得了对于测试点
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = 1010;
struct Point {
int x, y;
} a[M];
int n, K, ans;
bool mp[N][N];
int dp[N][N][N];
bool vis[M];
int sum;
int hasPoint(int x, int y) {
for (int i = 1; i <= n; i++) {
if (a[i].x == x && a[i].y == y) {
return i;
}
}
return -1;
}
void dfs(int dep, int cnt) {
if (vis[dep]) return;
vis[dep] = 1;
sum = max(sum, cnt);
int np = hasPoint(a[dep].x, a[dep].y + 1);
if (np != -1) {
dfs(np, cnt + 1);
}
np = hasPoint(a[dep].x + 1, a[dep].y);
if (np != -1) {
dfs(np, cnt + 1);
}
}
int main() {
scanf("%d%d", &n, &K);
if (K == 0) {
for (int i = 1; i <= n; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
}
for (int i = 1; i <= n; i++) {
memset(vis, 0, sizeof(vis));
sum = 0;
dfs(i, 1);
ans = max(ans, sum);
}
printf("%d\n", ans);
return 0;
}
for (int i = 1; i <= n; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
mp[a[i].x][a[i].y] = 1;
}
for (int i = 1; i < N; i++) {
for (int j = 1; j < N; j++) {
for (int k = 0; k <= K; k++) {
if (mp[i][j]) {
dp[i][j][k] = max(dp[i][j - 1][k], dp[i - 1][j][k]) + 1;
} else if (k) {
dp[i][j][k] = max(dp[i][j - 1][k - 1], dp[i - 1][j][k - 1]) + 1;
}
ans = max(ans, dp[i][j][k]);
}
}
}
printf("%d\n", ans);
return 0;
}