给定序列。能否将重新排列,使得?
如果能将重新排列使得,输出Yes
;如果不能,输出No
。
输出 | |
---|---|
Yes |
|
No |
|
Yes |
很容易想到,如果,则或必定成立。
因此,我们可以先把按升序排列,再是否成立即可。
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int a[3];
scanf("%d%d%d", a, a + 1, a + 2);
sort(a, a + 3);
puts(a[2] - a[1] == a[1] - a[0]? "Yes": "No");
return 0;
}
有坐山。第坐山有一个名字和高度。
输出第二高的山的名字。
由大小写英文字母和数字组成。
输出第二高的山的名字。
3
Everest 8849
K2 8611
Kangchenjunga 8586
K2
第二高的山是K2
。
4
Kita 3193
Aino 3189
Fuji 3776
Okuhotaka 3190
Kita
第二高的山是Kita
。
4
QCFium 2846
chokudai 2992
kyoprofriends 2432
penguinman 2390
QCFium
第二高的山是QCFium
。
这道题其实就是给定求数组中第二大的元素的。我们可以利用优先队列实现求第二大的元素。
#include <iostream>
#include <queue>
#include <string>
using namespace std;
using pis = pair<int, string>;
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n;
cin >> n;
priority_queue<pis, vector<pis>, greater<pis> > q;
while(n--)
{
string s;
int h;
cin >> s >> h;
q.emplace(h, s);
if(q.size() > 2) q.pop();
}
cout << q.top().second << endl;
return 0;
}
有一个四位的PIN。这个PIN由0
~9
组成,也可能以0
开头。
有一个字符串,代表每一种数字是否在这个PIN中出现:
o
,这个PIN肯定包含数字;x
,这个PIN肯定不包含数字;?
,这个PIN可能包含(也可能不包含)数字。有多少个合法的PIN?
是一个由o
、x
、?
组成的长度为的字符串。
将答案输出为一个整数。
答案 | |
---|---|
ooo???xxxx |
|
o?oo?oxoxo |
|
xxxxx?xxxo |
|
极端测试点:?????????? ,正确输出: |
因为可能的PIN数量非常少(最多只有个),所以我们考虑暴力枚举所有可能的PIN,即尝试0000
到9999
之间所有的PIN。对于每个可能的PIN,我们可以在的时间内判断出它是否合法。
程序的总时间复杂度为,由于和都是常数,所以也可以看作。
#include <cstdio>
using namespace std;
char s[15];
inline bool valid(int a, int b, int c, int d)
{
bool used[10] = {false};
used[a] = used[b] = used[c] = used[d] = true;
for(int i=0; i<10; i++)
if(s[i] == 'o')
{
if(!used[i])
return false;
}
else if(s[i] == 'x' && used[i])
return false;
return true;
}
int main()
{
scanf("%s", s);
int ans = 0;
for(int a=0; a<10; a++)
for(int b=0; b<10; b++)
for(int c=0; c<10; c++)
for(int d=0; d<10; d++)
ans += valid(a, b, c, d);
printf("%d\n", ans);
return 0;
}
我们有一个的棋盘,它上面每个小格子都是蓝色或红色的。棋盘上这个点的颜色取决于。如果+
,则为蓝;如果-
,则为红。
在棋盘上有一颗棋子,它的初始位置在左上角,也就是。Takahashi和Aoki要用这颗棋子对战。两人一开始都有分,他们要轮流执行如下操作,Takahashi先走:
当棋子走到时,游戏结束。此时,如果两人得分相等,则视为平局;否则,得分多的人胜利。
当两人都按最优操作进行游戏时,求最终的游戏结果。
是+
或-
。
如果Takahashi会赢,输出Takahashi
;如果Aoki,输出Aoki
;否则,游戏平局,输出Draw
。
略,请自行前往AtCoder查看。
本题可以使用动态规划的思想。
我们设为,则Takahashi的目标是最大化、Aoki的目标是最小化。我们很容易想到,对于棋子在时,如果是奇数,则Aoki走棋,如果它是偶数,则Takahashi走棋。
所以,对于棋盘上的每个点我们考虑如下:
我们设为玩家把棋子走到获得的分数,则有如下状态:
所以,最终我们只需要通过判断结果即可。如果,则Takahashi胜;如果,Aoki胜;否则,游戏平局。
程序的总时间复杂度为。
注意:我这里的dp运用了滚动表的技巧,所以是一维的,当然也可以使用普通的二维dp。
#include <cstdio>
#include <algorithm>
#define maxn 2005
using namespace std;
int dp[maxn], add[maxn][maxn];
int main()
{
int h, w;
scanf("%d%d", &h, &w);
for(int i=0; i<h; i++)
{
char tmp[maxn];
scanf("%s", tmp);
for(int j=0; j<w; j++)
add[i][j] = tmp[j] == '+'? 1: -1;
}
dp[w - 1] = 0;
for(int j=w-2; j>=0; j--)
dp[j] = j + h & 1? dp[j + 1] + add[h - 1][j + 1]: dp[j + 1] - add[h - 1][j + 1];
for(int i=h-2; i>=0; i--)
{
dp[w - 1] = i + w & 1? dp[w - 1] + add[i + 1][w - 1]: dp[w - 1] - add[i + 1][w - 1];
for(int j=w-2; j>=0; j--)
if(i + j & 1)
dp[j] = min(dp[j] - add[i + 1][j], dp[j + 1] - add[i][j + 1]);
else dp[j] = max(dp[j] + add[i + 1][j], dp[j + 1] + add[i][j + 1]);
}
if(dp[0] > 0) puts("Takahashi");
else if(dp[0] < 0) puts("Aoki");
else puts("Draw");
return 0;
}
我们有一棵由个顶点组成的加权树。第条边双向连接着顶点和且有一个权值。
对于一对顶点(),我们如下定义:
输出每对点的之和,对取模,即。
输出每对点的之和,对取模。
略,请自行前往AtCoder查看
首先,我们先看数据范围。
这样一来,最暴力的解法,即枚举所有对点、找最短路就肯定不行了。
其次,我们尝试优化暴力过程,考虑异或()的几个特征:
最后一个特征(异或再异或会抵消掉)实际上就是在告诉我们,,因为的最短路径中到的多余的一部分直接被最后一次异或抵消掉了。如果不能理解上面的证明,可以用下面的方法证明(设为和的最小共同祖先):
这时,我们可以令,并从开始跑一遍搜索,计算出所有的(时间复杂度),再对所有的求出所有的并求和(时间复杂度),算出结果。这样做的总时间复杂度为。可惜,这样还是过不去。
我们考虑进一步优化。我们发现,对于每个二进制位,在异或的操作下,一个和一个就能组成一个。所以,我们可以统计每一位的和的个数,计算它们的乘积并相加即可。
这里的搜索推荐,因为这道题中它比好写且更快,当然也可以实现。
#include <cstdio>
#include <queue>
#pragma GCC optimize("Ofast")
#define maxn 200005
#define MOD 1000000007LL
using namespace std;
using LL = long long;
vector<pair<int, LL>> G[maxn];
LL d[maxn];
int main()
{
int n;
scanf("%d", &n);
for(int i=1; i<n; i++)
{
int u, v;
LL w;
scanf("%d%d%lld", &u, &v, &w);
G[--u].emplace_back(--v, w);
G[v].emplace_back(u, w);
}
queue<int> q;
q.push(0);
for(int i=1; i<n; i++) d[i] = -1;
while(!q.empty())
{
int v = q.front(); q.pop();
for(auto [u, w]: G[v])
if(d[u] == -1)
q.push(u), d[u] = d[v] ^ w;
}
LL ans = 0LL;
for(int i=0; i<60; i++)
{
int cnt = 0;
for(int j=0; j<n; j++)
if(d[j] >> i & 1LL)
cnt ++;
if((ans += (1LL << i) % MOD * cnt % MOD * (n - cnt) % MOD) > MOD)
ans -= MOD;
}
printf("%lld\n", ans);
return 0;
}