给定三个整数,如果它们中有两个相等,输出另一个;否则,输出。
如果中有两个相等,输出另一个;否则,输出。
输出 | |||
---|---|---|---|
题还是一如既往的水……直接暴力判断三种相等的情况即可。
#include <cstdio>
using namespace std;
int main()
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(a == b) printf("%d\n", c);
else if(b == c) printf("%d\n", a);
else if(a == c) printf("%d\n", b);
else puts("0");
return 0;
}
给定和,求。
输出。
输出 | ||
---|---|---|
本题可以直接暴力,但我使用的是如下算法:
根据且,则有如下推导:
这样,我们就可以直接通过公式计算出结果了。
#include <cstdio>
using namespace std;
inline int sum(int x) { return x * (x + 1) >> 1; }
int main()
{
int n, k;
scanf("%d%d", &n, &k);
printf("%d\n", sum(n) * k * 100 + sum(k) * n);
return 0;
}
有个村庄,分别为村庄,相邻两个村庄之间的过路费是元。
Taro一开始有元且在村庄。他想要到达编号尽可能大的村庄。
他有个朋友。第个朋友会在Taro到达村庄时给他元。
求Taro最后到达的村庄的编号。
输出Taro最后到达的村庄的编号。
2 3
2 1
5 10
4
5 1000000000
1 1000000000
2 1000000000
3 1000000000
4 1000000000
5 1000000000
6000000000
请不要使用位整数。
3 2
5 5
2 1
2 2
10
Taro在一个村庄可能有多个朋友。
根据题目中的数据范围,我们可以证明答案严格小于,所以我们使用unsigned long long
作为存储数据类型。
可是,由于村庄数量还是太多,我们仍然无法依次模拟到达每个村庄。
我们发现较小,所以我们可以从朋友的角度考虑。
我们可以按排序所有朋友(的顺序不重要),这样就能把整个行程形成分成若干个区间,并依次判断每个区间是否能走完即可。
注意:我这里排序使用的是优先队列(priority_queue
)。
#include <cstdio>
#include <queue>
#define maxn 200005
#define INF 18446744073709551615ULL
using namespace std;
using ULL = unsigned long long;
using pll = pair<ULL, ULL>;
int main()
{
int n;
ULL k;
scanf("%d%llu", &n, &k);
priority_queue<pll, vector<pll>, greater<pll> > q;
for(int i=0; i<n; i++)
{
ULL a, b;
scanf("%llu%llu", &a, &b);
q.emplace(a, b);
}
ULL lastv = 0ULL;
q.emplace(INF, 0ULL);
while(!q.empty())
{
auto [a, b] = q.top(); q.pop();
ULL cost = a - lastv;
if(k < cost)
{
printf("%llu\n", lastv + k);
return 0;
}
k -= cost;
lastv = a, k += b;
}
return 0;
}
给定一个的正方形矩阵,第行第列的元素是。
求中所有的的子矩阵的中间值的最小值。
一个的正方形的中间值为其中第大的值。
如果不能理解题意,请看下图:
对应的输入输出:
3 2
5 9 8
2 1 3
7 4 6
/
2
输出答案。
3 2
1 7 0
5 8 11
10 4 2
4
我们有四个的正方形:。
我们依次从每个的元素中取第大的:
最后,我们从中选出最小的:。
3 3
1 2 3
4 5 6
7 8 9
5
本题可以二分答案。我们判定一个数是否为一个的正方形的中间值时,只需要计算这个正方形内严格大于这个数的数的个数是否为即可。
因此,我们可以使用矩阵前缀和快速计算一个正方形内严格大于一个数的数的数的个数。
总时间复杂度。
#include <cstdio>
#define maxn 805
#define INF 2147483647
using namespace std;
int a[maxn][maxn], dp[maxn][maxn], n, k, target;
inline int count(int x1, int y1, int x2, int y2)
{
return dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1];
}
inline bool check(int x)
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + (a[i][j] > x);
for(int x2=k; x2<=n; x2++)
for(int y2=k; y2<=n; y2++)
{
int x1 = x2 - k + 1, y1 = y2 - k + 1;
if(count(x1, y1, x2, y2) < target)
return true;
}
return false;
}
int main()
{
scanf("%d%d", &n, &k);
target = (k * k >> 1) + 1;
int l = INF, r = 0, ans = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
scanf("%d", a[i] + j);
if(a[i][j] > r) r = a[i][j];
if(a[i][j] < l) l = a[i][j];
}
while(l <= r)
{
int mid = l + r >> 1;
if(check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
printf("%d\n", ans);
return 0;
}
有一个的正方形棋盘,行数、列数下标都依次从到。我们用表示棋盘上行列的位置。
我们有一颗棋子,初始位置在。棋盘上有个黑方格,第个的位置在,其余都是白方格。
当棋子在时,你可以执行任意下列操作,但不能移出棋盘:
棋盘上的方格不能移动。求棋盘的最后一行的能到达的列的个数。
互不相等。
输出棋盘的最后一行的能到达的列的个数。
2 4
1 1
1 2
2 0
4 2
3
我们可以将棋子移动到、和,如下:
我们不能移动到或,所以输出。
1 1
1 1
0
我们无法移动棋子。
我们发现,当较大时,大多数行多是空着的,所以我们从每个开始考虑。对于白色的位置,如果不能到达,则不能到达。相反,对于黑色的,如果能到达或,则能到达。
因此,我们先排序每个,再对于每个有黑色的行,用set
维护能到达的列数,再按上述方法判断即可。
#include <cstdio>
#include <set>
#include <vector>
#include <algorithm>
#pragma GCC optimize("Ofast")
using namespace std;
int main()
{
int n, m;
scanf("%d%d", &n, &m);
vector<pair<int, int> > black;
black.reserve(m);
while(m--)
{
int x, y;
scanf("%d%d", &x, &y);
black.emplace_back(x, y);
}
m = black.size();
sort(black.begin(), black.end());
set<int> cols;
cols.insert(n);
for(int l=0, r=0; l<m; l=r)
{
while(r < m && black[r].first == black[l].first) r ++;
vector<int> rem, add;
for(int i=l; i<r; i++)
{
int y = black[i].second;
bool ok = cols.count(y - 1) || cols.count(y + 1);
if(cols.count(y))
{
if(!ok)
rem.push_back(y);
}
else if(ok)
add.push_back(y);
}
for(int y: rem) cols.erase(y);
for(int y: add) cols.insert(y);
}
printf("%llu\n", cols.size());
return 0;
}